目录
漏洞简介
什么是开放重定向(Open Redirect)?
开放重定向漏洞允许攻击者控制应用程序的重定向目标,将用户重定向到任意外部网站。虽然看似危害较小,但可用于钓鱼攻击和绕过安全控制。
HTTP重定向机制:
1 | // 方法1:HTTP响应头 |
攻击场景:
1 | 合法使用: |
危害:
钓鱼攻击
- 用户信任合法域名
- 被重定向到伪造网站
- 输入凭证被窃取
绕过安全控制
- 绕过URL黑名单
- 绕过SSRF防护
- 绕过CSP策略
会话劫持
- 重定向时泄露Session ID
- Referer头包含敏感信息
恶意软件分发
- 利用信任关系传播恶意软件
利用链:
1 | 1. 攻击者发送:https://bank.com/redirect?url=https://evil.com/fake-login |
DVWA场景:
一个登录后的重定向功能,用于跳转到指定页面。
Low 难度
攻击目标
完全不验证重定向目标,可重定向到任意URL。
后端代码分析
1 |
|
HTML表单:
1 |
|
漏洞分析
核心问题:
- 无URL验证 - 接受任意URL
- 无域名检查 - 不限制目标域名
- 无协议检查 - http、https、javascript:都接受
- 无白名单 - 没有允许的URL列表
攻击数据流:
1 | 用户输入: ?redirect=https://evil.com |
攻击步骤
步骤1:基础重定向攻击
测试1:重定向到外部网站
1 | URL: ?redirect=https://google.com |
步骤2:构造钓鱼攻击
创建伪造登录页面(evil.com/fake-login.html):
1 |
|
攻击链接:
1 | https://dvwa.local/vulnerabilities/redirect/?redirect=https://evil.com/fake-login.html |
steal.php(窃取凭证):
1 |
|
步骤3:使用JavaScript协议
1 | URL: ?redirect=javascript:alert('XSS') |
步骤4:绕过简单的协议检查
1 | 如果代码只检查http/https: |
步骤5:结合XSS攻击
1 | <!-- 如果重定向参数也被输出到页面 --> |
Medium 难度
攻击目标
简单的域名过滤,但可以绕过。
后端代码分析
1 |
|
新增防护
- 正则检查 - 检查URL是否包含合法域名
- 协议限制 - 只允许http/https
仍存在的漏洞
核心问题:正则表达式使用不当
1 | // 错误的正则:只要包含example.com就通过 |
绕过方法
方法1:域名后缀绕过
1 | 注册域名:example.com.evil.com |
方法2:使用@符号
1 | URL: ?redirect=http://example.com@evil.com |
方法3:URL参数绕过
1 | URL: ?redirect=http://evil.com?ref=http://example.com |
方法4:Fragment绕过
1 | URL: ?redirect=http://evil.com#http://example.com |
方法5:URL编码绕过
1 | URL: ?redirect=http://evil.com%3Furl%3Dhttp://example.com |
High 难度
攻击目标
更严格的域名检查,但仍有绕过可能。
后端代码分析
1 |
|
新增防护
- parse_url()解析 - 正确解析URL结构
- 白名单检查 - 只允许特定域名
- 检查host字段 - 验证域名部分
仍存在的漏洞
可能的绕过:
- URL解析差异 - 不同解析器对URL的理解不同
- 协议相对URL - //example.com
- 端口号绕过 - example.com:80
- IPv6绕过 - [::1]
绕过方法
方法1:利用解析器差异
1 | 某些情况下,parse_url()和浏览器解析URL的方式不同 |
方法2:协议相对URL
1 | 如果允许的白名单没有检查协议: |
方法3:端口绕过
1 | URL: ?redirect=http://example.com:8080@evil.com |
实际测试:
1 | import requests |
Impossible 难度
攻击目标
完善的URL验证,真正安全。
后端代码分析
1 |
|
HTML表单(包含CSRF token):
1 | <form method="GET"> |
完善的防护机制
多层防御:
- CSRF Token - 防止跨站请求伪造
- 严格白名单 - 只允许预定义的URL
- 完全匹配 - 不是部分匹配
- 协议验证 - 只允许http/https
- 域名验证 - 只允许指定域名
- 端口验证 - 只允许标准端口
- 审计日志 - 记录所有失败尝试
- 不泄露信息 - 错误消息统一
验证流程:
1 | 用户选择重定向目标 |
为什么无法攻破?
所有攻击都被阻止:
1 | 攻击1:?redirect=https://evil.com |
关键防御点:
- 白名单机制 - 默认拒绝,只允许明确列出的URL
- 完全匹配 - 不接受任何变体
- 多层验证 - 协议、域名、端口都检查
- CSRF防护 - 防止攻击者构造恶意链接
- 审计日志 - 记录所有异常
防御建议
代码层面
1. 使用白名单(最佳方案)
1 | // 定义允许的重定向URL |
2. 只允许相对路径
1 | // 只允许站内跳转 |
3. 验证域名
1 | function isAllowedDomain($url) { |
4. 使用映射而非直接URL
1 | // 使用ID映射到URL |
5. 添加确认页面
1 | // 重定向到外部网站前显示警告 |
框架层面
Laravel示例
1 | // 使用Laravel的重定向 |
Express.js示例
1 | app.get('/redirect', (req, res) => { |
监控层面
1. 记录所有重定向
1 | function logRedirect($user, $target, $success) { |
2. 检测异常重定向模式
1 | // 检测大量失败的重定向尝试 |
总结对比
| 特性 | Low | Medium | High | Impossible |
|---|---|---|---|---|
| URL验证 | ❌ 无 | 正则包含 | parse_url | 严格白名单 |
| 域名检查 | ❌ | 弱检查 | 白名单 | 严格白名单 |
| 协议检查 | ❌ | http/https | http/https | http/https |
| 匹配方式 | N/A | 包含匹配 | 精确匹配 | 完全匹配 |
| CSRF防护 | ❌ | ❌ | ❌ | ✅ |
| 审计日志 | ❌ | ❌ | ❌ | ✅ |
| 攻击难度 | 极易 | 简单 | 中等 | 极难 |
常用Payload集合
基础Payload
1 | # 外部重定向 |
绕过技巧
1 | # 域名后缀 |
实战建议
渗透测试清单:
- ✅ 测试是否接受外部URL
- ✅ 尝试各种协议(http, https, javascript, data)
- ✅ 测试@符号绕过
- ✅ 测试域名后缀绕过
- ✅ 测试URL参数/fragment绕过
- ✅ 测试解析器差异
- ✅ 检查是否有确认页面
防御清单:
- ✅ 使用白名单
- ✅ 只允许相对路径(如果可能)
- ✅ 验证协议、域名、端口
- ✅ 使用ID映射
- ✅ 添加确认页面(外部跳转)
- ✅ 记录所有重定向
- ✅ 实施CSRF防护
道德准则:
- 只在授权环境测试
- 不构造真实钓鱼页面
- 学习是为了防御开放重定向攻击