开放重定向是什么
应用把用户可控参数直接当作跳转目标(redirect、next、returnUrl、continue、callback 等),攻击者可构造指向外部站点的链接。链接域名看起来是可信站点,落地页却是钓鱼页面;在 OAuth 或单点登录场景里,回调参数还可被用于诱导凭据泄露。防护思路是只允许站内相对路径,或用跳转映射表把键映射到固定地址。
基本信息
| 常见参数 | redirect、next、returnUrl、continue、callback、url |
|---|---|
| 风险后果 | 钓鱼跳转、凭据诱导、OAuth 回调劫持 |
| 防护方式 | 站内相对路径校验或白名单映射表 |
| 校验时机 | URL 解码与规范化之后 |
| 典型位置 | 登录成功跳转、注销回跳、支付回跳 |
典型使用场景
- 登录后跳转:/login?next=... 最常见的开放重定向入口
- OAuth 回调:redirect_uri 校验不严会被用于窃取授权码
- 注销回跳:/logout?returnUrl=... 常被当作无害功能忽略
- 多语言站点跳转:语言切换后回到指定页面
- 短链与分享链接:落地页参数透传时易被外部地址替换
安全校验写法
安全校验写法
from urllib.parse import unquote
def safe_next(raw):
v = unquote(raw or "") # 先统一解码,避免编码绕过
if not v.startswith("/") or v.startswith("//") or v.startswith("/\\"):
return "/" # 拒绝协议相对地址与反斜杠变体
return v
# 更稳妥的做法:跳转目标用映射表,如 {"home":"/", "orders":"/orders"}
# 前端只传键,服务端查表,彻底消除用户可控的地址拼接常见参数与场景
| 参数 | 典型场景 | 需注意的绕过 |
|---|---|---|
| next | 登录后跳转 | //evil.example 与 /\evil.example |
| returnUrl | 注销或审批回跳 | %2f%2f 等编码形式 |
| redirect_uri | OAuth 授权回调 | 子串匹配白名单可被构造域名绕过 |
| url | 参数透传跳转 | 大小写与尾部空白绕过 |
校验必须在 URL 解码与路径规范化之后进行:先解码再判断,才能覆盖 %2f%2f、%5c 这类编码形式;反过来先判断再解码等于没判。
OAuth 场景的 redirect_uri 应做完整字符串白名单比对,不要用『包含本站域名』这类子串判断——把本站域名写进攻击者 URL 的查询串就能绕过。