开放重定向漏洞
| , 4 minutes reading.
1. 定义
开放重定向 (Open Redirect) 漏洞发生在 Web 应用程序接受用户控制的参数,并在未经适当验证的情况下使用它将用户重定向到外部 URL。
虽然开放重定向本身看起来危害较低,但它们对攻击者非常有价值,因为它们滥用了用户对合法域名的信任。使用 trusted-bank.com/redirect?url=evil.com 的钓鱼链接比直接指向 evil.com 的链接看起来更合法。
2. 技术原理
许多合法应用程序需要重定向功能:
- 登录后重定向:在认证后将用户返回到其原始页面
- 营销追踪:在到达目的地之前通过追踪系统重定向
- 单点登录:在身份提供者和应用程序之间重定向
易受攻击的模式:
https://example.com/login?redirect=https://evil.com成功登录后,应用程序在未经验证的情况下重定向到 evil.com。
常见的易受攻击参数:
redirect、redirect_uri、return、returnUrlnext、url、target、destinationcontinue、goto、out、redir
绕过技术: 攻击者使用各种技巧绕过弱验证:
# 基本
?redirect=https://evil.com
# 协议相对
?redirect=//evil.com
# 域名混淆
?redirect=https://example.com.evil.com
?redirect=https://[email protected]
?redirect=https://evil.com/example.com
# URL 编码
?redirect=https%3A%2F%2Fevil.com
# 参数污染
?redirect=https://example.com&redirect=https://evil.com3. 攻击流程
sequenceDiagram
participant Victim as 受害者
participant Attacker as 攻击者
participant TrustedSite as 受信任网站
participant PhishingSite as 钓鱼网站
Attacker->>Victim: 发送带有链接的钓鱼邮件<br/>trusted-bank.com/redirect?url=evil.com
Note over Victim: 链接看起来合法<br/>域名是 trusted-bank.com
Victim->>TrustedSite: 点击链接到 trusted-bank.com
TrustedSite->>TrustedSite: 处理重定向参数
TrustedSite-->>Victim: 302 重定向到 evil.com
Victim->>PhishingSite: 浏览器跟随重定向
Note over PhishingSite: 伪造的登录页面<br/>与 trusted-bank.com 完全相同
Victim->>PhishingSite: 输入凭据
PhishingSite->>Attacker: 凭据被捕获4. 真实案例:Google OAuth 开放重定向 (2016)
目标: Google OAuth 2.0 认证流程。 漏洞类别: OAuth 回调中的开放重定向。
漏洞背景: 2016 年,研究员 Egor Homakov 发现 Google 的 OAuth 实现在 redirect_uri 参数验证中存在开放重定向漏洞。
攻击过程:
- OAuth 要求应用程序注册允许的
redirect_uri值。 - Google 对某些注册域名的验证过于宽松。
- 攻击者可以找到一个在其自身域上存在开放重定向的合法应用程序。
- 链条:Google OAuth -> 合法应用(存在开放重定向)-> 攻击者网站。
攻击链示例:
1. 用户点击: accounts.google.com/oauth?redirect_uri=legitimate-app.com
2. Google 验证: legitimate-app.com 已注册 - 通过
3. Google 重定向到: legitimate-app.com/callback?code=AUTH_CODE
4. legitimate-app.com 存在开放重定向: /goto?url=evil.com
5. 攻击者收到: evil.com?code=AUTH_CODE
6. 攻击者用 code 交换访问令牌影响: 这允许攻击者通过链接漏洞窃取 OAuth 令牌。Google 加强了其 redirect_uri 验证,并鼓励使用更严格的匹配模式。
5. 深度防御策略
A. 白名单验证
仅允许重定向到预先批准的目的地。
const ALLOWED_DOMAINS = [
'example.com',
'subdomain.example.com',
'partner-site.com'
];
function validateRedirect(url) {
try {
const parsed = new URL(url);
return ALLOWED_DOMAINS.includes(parsed.hostname);
} catch {
return false;
}
}B. 仅允许相对 URL
将重定向限制为相对路径(仅限同源)。
function safeRedirect(url) {
// 仅允许以 / 开头的路径
if (url.startsWith('/') && !url.startsWith('//')) {
return url;
}
return '/'; // 默认安全重定向
}警告: 注意协议相对 URL(//evil.com)。
C. 间接引用映射
使用令牌代替直接 URL。
const REDIRECT_MAP = {
'dashboard': '/user/dashboard',
'settings': '/user/settings',
'logout': '/auth/logout'
};
// 用法: /redirect?target=dashboard
function handleRedirect(target) {
const destination = REDIRECT_MAP[target];
if (destination) {
return redirect(destination);
}
return redirect('/');
}D. 用户确认
对于外部重定向,显示警告页面。
<div class="redirect-warning">
<h2>您即将离开 example.com</h2>
<p>您正在被重定向到外部网站:</p>
<p><strong>https://external-site.com</strong></p>
<p>我们不对外部网站的内容负责。</p>
<a href="https://external-site.com">继续</a>
<a href="/">返回 example.com</a>
</div>E. 严格的 OAuth 配置
对于 OAuth 实现:
- 精确匹配: 要求
redirect_uri精确匹配,而非前缀匹配。 - 禁止通配符: 避免在注册的重定向 URI 中使用通配符模式。
- 仅限 HTTPS: 在生产环境中仅允许 HTTPS 重定向 URI。
# 好:仅精确匹配
已注册: https://app.example.com/oauth/callback
有效: https://app.example.com/oauth/callback
无效: https://app.example.com/oauth/callback/evil
# 坏:前缀匹配
已注册: https://app.example.com/
有效: https://app.example.com/anything <- 危险