Open HTTP Redirect 开放重定向漏洞:URL 跳转校验缺陷与绕过技术
-
- 前言
- [1. Open HTTP Redirect 核心理论基础](#1. Open HTTP Redirect 核心理论基础)
-
- [1.1 漏洞本质与定义](#1.1 漏洞本质与定义)
- [1.2 漏洞成立的三大必要条件](#1.2 漏洞成立的三大必要条件)
- [1.3 完整钓鱼攻击链路](#1.3 完整钓鱼攻击链路)
- [1.4 服务端跳转 vs 客户端跳转(DOM 型)](#1.4 服务端跳转 vs 客户端跳转(DOM 型))
- [1.5 常见攻击场景与业务危害](#1.5 常见攻击场景与业务危害)
- [1.6 漏洞在安全榜单中的定位](#1.6 漏洞在安全榜单中的定位)
- [2. DVWA Open HTTP Redirect(Low)](#2. DVWA Open HTTP Redirect(Low))
-
- [2.1 页面黑盒探测](#2.1 页面黑盒探测)
- [2.2 黑盒漏洞利用实操](#2.2 黑盒漏洞利用实操)
-
- [2.2.1 直接构造恶意跳转 URL](#2.2.1 直接构造恶意跳转 URL)
- [2.2.2 伪装可信域名钓鱼链接(实战场景)](#2.2.2 伪装可信域名钓鱼链接(实战场景))
- [2.3 源码审计(无校验直接跳转)](#2.3 源码审计(无校验直接跳转))
- [3. DVWA Open HTTP Redirect(Medium)](#3. DVWA Open HTTP Redirect(Medium))
-
- [3.1 黑盒探测](#3.1 黑盒探测)
-
- [3.1.1 基础功能测试](#3.1.1 基础功能测试)
- [3.1.2 验证协议过滤防护机制](#3.1.2 验证协议过滤防护机制)
- [3.1.3 黑盒推导校验规则](#3.1.3 黑盒推导校验规则)
- [3.2 黑盒攻击实操](#3.2 黑盒攻击实操)
-
- [3.2.1 协议相对 URL 绕过原理](#3.2.1 协议相对 URL 绕过原理)
- [3.2.2 构造 `//evil.com` 恶意 Payload](#3.2.2 构造
//evil.com恶意 Payload) - [3.2.3 攻击复现步骤](#3.2.3 攻击复现步骤)
- [3.2.4 正则过滤存在的逻辑缺陷](#3.2.4 正则过滤存在的逻辑缺陷)
- [3.3 源码审计](#3.3 源码审计)
- [4. DVWA Open HTTP Redirect(High)](#4. DVWA Open HTTP Redirect(High))
-
- [4.1 黑盒探测](#4.1 黑盒探测)
-
- [4.1.1 抓包对比 Low/Medium 行为差异](#4.1.1 抓包对比 Low/Medium 行为差异)
- [4.1.2 复用 Medium 的 Payload 测试(完全失效)](#4.1.2 复用 Medium 的 Payload 测试(完全失效))
- [4.1.3 黑盒推导校验规则](#4.1.3 黑盒推导校验规则)
- [4.2 黑盒攻击绕过实操](#4.2 黑盒攻击绕过实操)
-
- [4.2.1 子串匹配校验漏洞原理](#4.2.1 子串匹配校验漏洞原理)
- [4.2.2 外部域名拼接 info.php 构造 Payload](#4.2.2 外部域名拼接 info.php 构造 Payload)
- [4.2.3 完整攻击复现](#4.2.3 完整攻击复现)
- [4.3 High 级别源码审计](#4.3 High 级别源码审计)
- [5. DVWA Open HTTP Redirect(Impossible)](#5. DVWA Open HTTP Redirect(Impossible))
-
- [5.1 源码审计](#5.1 源码审计)
- [5.2 四级对比总结(Low/Medium/High/Impossible)](#5.2 四级对比总结(Low/Medium/High/Impossible))
- [5.3 最终安全修复方案](#5.3 最终安全修复方案)
- 免责声明
前言
上一篇我们详细拆解了 CSRF 跨站请求伪造漏洞的攻防全流程,相信大家对"借助用户身份伪造请求"的攻击思路已经有了清晰的认识。今天我们继续 Web 漏洞系列,来聊一个经常被低估、但在真实钓鱼和社工攻击中极其好用的漏洞------Open HTTP Redirect(开放重定向)。
很多开发者觉得"不就是个跳转吗,能有什么危害",但恰恰是这种轻视,让开放重定向成为了钓鱼攻击的绝佳跳板 。一个存在漏洞的可信域名跳转 ,能让钓鱼链接的可信度提升数个等级 ,用户看到熟悉的域名后往往放松警惕,最终被诱导至恶意站点窃取账号凭证。
1. Open HTTP Redirect 核心理论基础
1.1 漏洞本质与定义
开放重定向漏洞(Open Redirect) ,又称 URL 跳转漏洞,对应的标准漏洞编号为 CWE-601: URL Redirection to Untrusted Site。
漏洞的本质一句话就能说清:Web 应用程序接收用户可控的参数来构造跳转目标 URL,但没有对该 URL 进行严格的合法性校验,导致攻击者可以构造恶意链接,将用户重定向到任意外部站点。
用最直白的话讲:网站有个跳转功能,本来是跳转到自己站内的页面,但因为没校验,攻击者可以改成跳转到钓鱼网站,而且链接前面还是正经域名,用户看不出来。
典型的漏洞 URL 长这样:
https://trusted-site.com/login?redirect=https://evil.com/phish
用户看到域名是 trusted-site.com(可信站点),放心点进去,结果啪一下就跳到了攻击者控制的 evil.com,整个过程行云流水,几乎没有感知。
1.2 漏洞成立的三大必要条件
不是所有带跳转的地方都有漏洞,必须同时满足以下三个条件:
条件一:跳转目标 URL 完全或部分由用户可控
- 参数名常见的有:
redirect、url、next、go、to、return_url、redirect_uri、jump、target等等 - 用户输入的内容能直接或间接影响最终的跳转地址
条件二:服务端未对跳转目标做严格的白名单校验
- 完全没校验
- 校验了但能被绕过
- 用了黑名单、关键字匹配等不靠谱的校验方式
条件三:跳转是服务端 3xx 响应或客户端自动触发
- 服务端通过
Location响应头触发 302/301 跳转(最常见) - 前端通过
window.location、meta refresh等方式跳转(DOM 型) - 用户不需要额外点击确认,访问即跳转
1.3 完整钓鱼攻击链路
开放重定向最经典的用法就是钓鱼,完整攻击链路分四步走:
第一步:寻找可信站点的跳转漏洞
攻击者在目标公司的官网、登录页、OAuth 授权页等地方,寻找存在开放重定向漏洞的 URL 参数。
第二步:构造恶意跳转链接
把正常的跳转目标替换成攻击者的钓鱼站点地址,得到一个"披着可信域名外衣"的恶意链接:
https://银行官网.com/login?redirect=https://钓鱼网站.com/fake-login
第三步:社工诱导用户点击
通过邮件、短信、QQ/微信等渠道,把链接发给受害者,话术通常是"您的账户异常,请点击链接登录核实"。
第四步:用户跳转至钓鱼站点被窃取信息
用户看到链接是正经银行域名,放下戒心点击 → 浏览器先访问银行官网 → 官网 302 跳转到钓鱼网站 → 钓鱼网站高仿银行登录页 → 用户输入账号密码 → 攻击者拿到凭证。
整个过程中,用户的注意力都在"域名是不是官方的"上,很少有人会去注意 URL 后面 ?redirect= 那串参数。
1.4 服务端跳转 vs 客户端跳转(DOM 型)
开放重定向按触发位置分两大类,攻击效果略有区别:
| 类型 | 触发位置 | 典型特征 | 可利用性 |
|---|---|---|---|
| 服务端重定向 | 后端代码 | 返回 302/301 状态码 + Location 头 | 高,最常见,钓鱼效果最好 |
| 客户端重定向(DOM型) | 前端 JS 代码 | window.location = url 跳转 |
中,可能被浏览器策略限制 |
额外提一句:DOM 型开放重定向在某些场景下甚至可以升级为 XSS------如果跳转支持 javascript: 伪协议的话,直接就能执行 JS 代码,危害直接上一个档次。
1.5 常见攻击场景与业务危害
很多人觉得开放重定向就是个"低危小漏洞",其实它的危害被严重低估了。
主要攻击场景:
-
钓鱼诈骗(最主流)
这是开放重定向的本职工作。用可信域名当幌子,把用户骗到高仿钓鱼页偷账号密码,成功率比直接发陌生域名高得多。
-
OAuth 授权令牌窃取
如果 OAuth 的
redirect_uri校验不严,或者可信域内存在开放重定向,攻击者可以把授权码/access_token 拐到自己的服务器,直接接管用户账号。 -
绕过 SSRF 防护
有些 SSRF 防护只校验请求的域名是不是内网,攻击者可以让服务端先请求一个带开放重定向的外网地址,再由重定向跳到内网,变相绕过防护。
-
恶意软件分发
把下载链接伪装成可信站点的跳转,用户以为是官方下载,实际下的是木马病毒。
-
绕过邮件安全网关
企业邮件网关通常会过滤恶意域名的链接,但开放重定向的链接主域名是可信的,很容易绕过检测进到用户收件箱。
1.6 漏洞在安全榜单中的定位
- CWE 编号:CWE-601 --- URL Redirection to Untrusted Site(开放重定向的标准定义)
- OWASP Top 10 :虽然没有单独列项,但常被归类到 A01:2021 - Broken Access Control (访问控制失效)或 A03:2021 - Injection(注入)的范畴,属于"不起眼但到处都是"的基础漏洞
- CTF 定位:属于 Web 方向的基础考点,经常和 SSRF、XSS、CSRF、OAuth 等知识点结合出题,单独考的话一般是送分题,但组合起来就是难题
- 漏洞评级 :单独的开放重定向一般评 低危到中危 ,但如果能结合 OAuth 偷 token、配合 SSRF 打内网,直接升级为 高危甚至严重
一句话总结:开放重定向本身伤害不高,但作为"攻击链的粘合剂"极其好用,经常是组合拳里的关键一环。
对,接下来就是 Low 级别,我们按黑盒探测 → 漏洞利用 → 源码审计的顺序来。
2. DVWA Open HTTP Redirect(Low)
2.1 页面黑盒探测
先不看源码,我们以渗透测试者的视角,先摸清楚这个页面的功能。

进入 DVWA 的 Open HTTP Redirect 模块,首先看到页面上有三个链接,分别指向 info.php?id=1、info.php?id=2、info.php?id=3,看起来是跳转到不同的信息页面。
随便点一个,比如第一个,抓包看一下:

黑盒初步结论:
base
GET /vulnerabilities/open_redirect/source/low.php?redirect=info.php?id=1 HTTP/1.1
- 存在一个
redirect参数,用来控制跳转目标 - 服务端返回 302 状态码,通过
Location头触发跳转 - 目前传的是站内相对路径
info.php?id=1
那问题来了:如果我把 redirect 参数改成一个外部网址,会发生什么?这就是我们要验证的漏洞点。
2.2 黑盒漏洞利用实操
Low 级别,顾名思义,就是最菜的级别,一般没有任何防护。我们直接来测。
2.2.1 直接构造恶意跳转 URL
测试思路: 把 redirect 参数的值直接换成一个外部域名,看能不能跳过去。
构造 Payload:
base
vulnerabilities/open_redirect/source/low.php?redirect=https://www.baidu.com

把这个 URL 在抓到的包里面改一下。

结果: 啪一下,很快啊,直接跳到百度首页了。
说明 Low 级别完全没有任何校验,你传什么 URL 它就跳什么,连是站内还是站外都不检查。
2.2.2 伪装可信域名钓鱼链接(实战场景)
光跳个百度没什么意思,我们来模拟真实的钓鱼场景。
假设攻击者的钓鱼网站是 https://evil.com/fake-login(高仿 DVWA 登录页),攻击者会构造这样的恶意链接:
base
http://你的DVWA地址/vulnerabilities/open_redirect/source/low.php?redirect=https://evil.com/fake-login
然后把这个链接发给受害者,话术比如:
"系统升级,请点击链接重新登录:http://你的DVWA地址/..."
受害者一看,域名是正经的 DVWA 地址(或者真实场景下是公司官网、银行官网),放心点进去,结果直接被重定向到钓鱼页面,输入账号密码就中招了。
为什么钓鱼成功率高?
- 链接主域名是可信的,用户不会怀疑
- 跳转过程是服务端 302,速度极快,用户几乎察觉不到
- 钓鱼页面可以做得和官方一模一样,普通用户根本分辨不出来
2.3 源码审计(无校验直接跳转)
Low 级别的源码非常简单,一共就几行,我们逐行来看:
php
<?php
// 第1步:检查 redirect 参数是否存在且不为空
if (array_key_exists ("redirect", $_GET) && $_GET['redirect'] != "") {
// 第2步:直接把 redirect 参数的值拼到 Location 头里,触发跳转
header ("location: " . $_GET['redirect']);
exit;
}
// 如果参数不存在或为空,返回500错误
http_response_code (500);
?>
<p>Missing redirect target.</p>
<?php
exit;
?>
代码逻辑拆解:
- 参数检查 :用
array_key_exists判断 GET 请求里有没有redirect参数,并且值不为空 - 直接跳转 :拿到参数值后,没有做任何校验 ,直接拼到
Location响应头里返回给浏览器 - 错误处理:参数缺失的话返回 500 状态码和提示文字
漏洞点就在第 4 行:
php
header ("location: " . $_GET['redirect']);
$_GET['redirect'] 是用户完全可控的输入,开发者没有检查它是不是站内地址、是不是合法域名、是不是允许的协议,直接就拿来跳转了。
你传 info.php?id=1 它跳站内页,你传 https://evil.com 它就跳恶意网站,照单全收。
一句话总结 Low 级别: 完全没有任何安全防护,属于"开发者根本没想过跳转功能会被滥用"的典型反面教材。
3. DVWA Open HTTP Redirect(Medium)
好,接下来 Medium 级别。开发者觉得 Low 太菜了,加了点防护,但是------没加对,照样能绕。
3.1 黑盒探测
还是老规矩,先不看源码,从黑盒视角一步步摸。
3.1.1 基础功能测试
先把 DVWA 难度切到 Medium,进入 Open HTTP Redirect 模块。
页面看起来和 Low 级别一模一样,还是三个链接,点一下试试:
base
vulnerabilities/open_redirect/source/medium.php?redirect=info.php?id=1

正常跳转,没问题,基础功能和 Low 一样。
3.1.2 验证协议过滤防护机制
那我们直接上 Low 级别的 Payload 试试,看还能不能用:
base
medium.php?redirect=https://www.baidu.com

结果: 页面报错了,提示 Absolute URLs not allowed.(不允许使用绝对URL)。

说明 Medium 级别确实加了防护,不让直接跳 http:// 或 https:// 开头的绝对地址。
那我们再试几个变种,看看防护到底有多严:
| 测试 Payload | 结果 |
|---|---|
https://baidu.com |
❌ 被拦截 |
http://baidu.com |
❌ 被拦截 |
HTTP://baidu.com |
❓ 试试大写 |
//baidu.com |
❓ 试试不带协议 |
ftp://baidu.com |
❓ 试试其他协议 |
3.1.3 黑盒推导校验规则
经过一轮测试,我们大概能摸出 Medium 的校验规则:
-
过滤了
http://和https://开头的绝对 URL- 只要参数里包含
http://或https://,就直接拒绝 - 大小写都试了,
HTTP://也被拦,说明正则是不区分大小写的
- 只要参数里包含
-
相对路径没问题
info.php?id=1这种站内相对路径正常跳转- 说明校验只针对"绝对URL",相对路径不受影响
-
那
//baidu.com这种不带协议的呢?- 这就是我们的突破口------协议相对 URL
3.2 黑盒攻击实操
3.2.1 协议相对 URL 绕过原理
先讲一个冷知识:URL 可以省略协议部分,只写 //域名,这种写法叫协议相对 URL(Protocol-relative URL)。
比如 //www.baidu.com,浏览器会自动使用当前页面的协议(http 或 https)来补全这个 URL。
举个例子:
- 你在
https://dvwa.com/页面上访问//evil.com - 浏览器会自动补全为
https://evil.com - 效果和写完整的
https://evil.com一模一样
为什么能绕过?
- Medium 的正则只过滤
http://和https://开头的字符串 - 协议相对 URL 是
//开头,不带http字样 - 正则匹配不到,直接放行了
- 但浏览器拿到
//evil.com照样能跳转到外部站点
完美绕过分检。
3.2.2 构造 //evil.com 恶意 Payload
知道原理就简单了,构造 Payload:
base
medium.php?redirect=//www.baidu.com
注意:前面没有 http: 或 https:,直接就是两个斜杠。
3.2.3 攻击复现步骤
第一步:构造恶意链接
base
http://你的DVWA地址/vulnerabilities/open_redirect/source/medium.php?redirect=//evil.com/fake-login
第二步:发给受害者
还是熟悉的社工话术,链接看起来还是正经的 DVWA 域名。
第三步:受害者点击跳转
用户点进去 → 服务端返回 302,Location 是 //evil.com/fake-login → 浏览器自动补全协议为 https://evil.com/fake-login → 成功跳转到钓鱼站点。
还有一种就是使用ftp://baidu.com
ftp://baidu.com:协议替换绕过,唤起系统 FTP 工具跳转外部站点;

传入该Payload后,Medium正则仅匹配http://、https://,不含ftp关键字,校验直接放行 。
浏览器接收到Location: ftp://baidu.com响应头,会触发系统弹窗询问是否打开对应应用(你截图里的跳转唤起弹窗就是这个原理),同样达成跳转到外部非信任站点的效果,属于第二种绕过思路。
3.2.4 正则过滤存在的逻辑缺陷
为什么开发者加了防护还是被绕了?核心问题出在两个地方:
缺陷一:只过滤了协议头,没考虑协议相对 URL
开发者想的是"只要不让写完整的 http/https URL 就安全了",但忘了还有 // 这种写法。
缺陷二:黑名单思路本身就不靠谱
用黑名单过滤危险字符/字符串,永远是被动防御,攻击者总能找到你没考虑到的变种。今天你过滤了 http://,明天还有 //、\\、javascript:、各种编码绕过......
一句话总结: 黑名单防御防不胜防,白名单才是正道。
3.3 源码审计
Medium 级别的源码如下,我们逐行拆解:
php
<?php
// 第1步:检查 redirect 参数是否存在且不为空
if (array_key_exists ("redirect", $_GET) && $_GET['redirect'] != "") {
// 第2步:正则匹配,检查参数里有没有 http:// 或 https://
if (preg_match ("/http:\/\/|https:\/\//i", $_GET['redirect'])) {
// 匹配到了 → 拦截,返回500错误
http_response_code (500);
?>
<p>Absolute URLs not allowed.</p>
<?php
exit;
} else {
// 没匹配到 → 直接跳转
header ("location: " . $_GET['redirect']);
exit;
}
}
// 参数缺失的情况
http_response_code (500);
?>
<p>Missing redirect target.</p>
<?php
exit;
?>
代码逻辑拆解:
- 参数校验 :先判断
redirect参数有没有传、是不是空 - 正则过滤 :核心防护就在第 4 行的
preg_match- 正则表达式:
/http:\/\/|https:\/\//i - 意思是:匹配
http://或者https://,末尾的/i表示不区分大小写 - 匹配到了就拦截,没匹配到就放行跳转
- 正则表达式:
防护的缺陷:
这个正则只认 http:// 和 https:// 两种协议,其他的一概不管。所以:
| Payload | 正则是否匹配 | 结果 |
|---|---|---|
http://evil.com |
✅ 匹配到 http:// |
❌ 拦截 |
https://evil.com |
✅ 匹配到 https:// |
❌ 拦截 |
//evil.com |
❌ 没有 http 字样 | ✅ 放行 → 协议相对URL绕过 |
ftp://evil.com |
❌ 是 ftp 不是 http | ✅ 放行 → 协议替换绕过 |
javascript:alert(1) |
❌ 没有 http | ✅ 放行 → 伪协议绕过(DOM型可用) |
一句话总结 Medium 级别: 用黑名单思路只封了 http/https 两个协议,没考虑协议相对 URL 和其他协议,属于"防了但没完全防"的典型反面教材。
好,接下来 High 级别。开发者觉得 Medium 的防护太菜了,换了个思路------强制要求跳转地址里必须包含 info.php,以为这样就只能跳站内页了。但还是太年轻。
4. DVWA Open HTTP Redirect(High)
4.1 黑盒探测
还是老规矩,先不看源码,从黑盒视角一步步摸。
4.1.1 抓包对比 Low/Medium 行为差异
把 DVWA 难度切到 High,进入 Open HTTP Redirect 模块。
页面看起来还是一样的,三个链接,点一下正常跳转:
base
high.php?redirect=info.php?id=1
正常跳转,没问题。
4.1.2 复用 Medium 的 Payload 测试(完全失效)
先试试 Low 和 Medium 的 Payload 还能不能用:
测试1:直接外部URL(Low 级别 Payload)
base
high.php?redirect=https://www.baidu.com
结果:报错,提示 You can only redirect to the info page.(你只能跳转到 info 页面)
测试2:协议相对URL(Medium 级别 Payload)
base
high.php?redirect=//www.baidu.com
结果:还是报错,同样的提示。
测试3:ftp协议绕过
base
high.php?redirect=ftp://baidu.com
结果:依然报错。
看来 Medium 级别的绕过手法在 High 这里完全失效了,防护升级了。
4.1.3 黑盒推导校验规则
报错信息很关键:You can only redirect to the info page.
"只能跳转到 info 页面"------那它是怎么判断你跳的是不是 info 页面的呢?
我们来做几组测试,摸清楚校验规则:
| 测试 Payload | 结果 | 推测 |
|---|---|---|
info.php?id=1 |
✅ 正常跳转 | 正常情况 |
info.php |
✅ 正常跳转 | 不带参数也可以 |
INFO.PHP |
❌ 报错 | 区分大小写 |
abcinfo.php |
✅ 正常跳转 | 前面加东西也行? |
info.php/../ |
✅ 正常跳转 | 后面加东西也可以? |
https://evil.com |
❌ 报错 | 没有 info.php 就不行 |
https://evil.com/info.php |
❓ 试试这个 |
关键测试:
base
high.php?redirect=https://evil.com/info.php
结果: 居然跳转了!虽然跳的是 https://evil.com/info.php(一个不存在的页面),但确实成功跳转到了外部域名 evil.com。
黑盒结论:
High 级别的校验规则是------只要 redirect 参数的值里包含 info.php 这个子串,就放行 ,不管这个 info.php 在 URL 的什么位置,也不管整个 URL 是不是站内地址。
这就好办了。
4.2 黑盒攻击绕过实操
4.2.1 子串匹配校验漏洞原理
High 级别用的是子串匹配 的校验思路:只要 URL 里有 info.php 这几个字,就认为你跳的是站内的 info 页面,是安全的。
但这个逻辑有个致命缺陷:info.php 可以出现在 URL 的任意位置,包括域名后面、参数里、路径里......
攻击者只要在恶意 URL 里随便找个地方塞上 info.php 这几个字,就能骗过校验。
4.2.2 外部域名拼接 info.php 构造 Payload
知道原理就简单了,我们有好几种构造方式:
方式一:路径拼接(最常用)
base
high.php?redirect=https://evil.com/info.php
把 info.php 当成恶意站点上的一个路径,骗过校验。
方式二:参数拼接(更隐蔽)
base
high.php?redirect=https://evil.com/phish?x=info.php
把 info.php 藏在 URL 参数里,不影响实际跳转目标。
方式三:锚点拼接
base
high.php?redirect=https://evil.com/phish#info.php
把 info.php 放在锚点(#后面),完全不影响页面跳转。
三种方式都能成功绕过,实战推荐用参数拼接,最隐蔽。
4.2.3 完整攻击复现
第一步:构造恶意钓鱼链接
base
http://你的DVWA地址/vulnerabilities/open_redirect/source/high.php?redirect=https://evil.com/fake-login?foo=info.php
注意看:redirect 参数的值是 https://evil.com/fake-login?foo=info.php
- 真实目标:
https://evil.com/fake-login(钓鱼页面) - 凑数用的:
?foo=info.php(只是为了骗过校验,不影响实际跳转)

第二步:发给受害者
链接主域名还是正经的 DVWA 地址,用户看不出问题。
第三步:受害者点击跳转
用户点进去 → 服务端检查到 URL 里有 info.php,放行 → 302 跳转到 https://evil.com/fake-login?foo=info.php → 钓鱼页面正常显示(那个 foo=info.php 参数对钓鱼页面毫无影响)。
完美绕过,效果和 Low 级别一模一样。
4.3 High 级别源码审计
High 级别的源码如下,我们逐行拆解:
php
<?php
// 第1步:检查 redirect 参数是否存在且不为空
if (array_key_exists ("redirect", $_GET) && $_GET['redirect'] != "") {
// 第2步:用 strpos 检查参数里有没有 "info.php" 这个子串
if (strpos($_GET['redirect'], "info.php") !== false) {
// 找到了 info.php → 认为是合法的,直接跳转
header ("location: " . $_GET['redirect']);
exit;
} else {
// 没找到 info.php → 拦截,返回500错误
http_response_code (500);
?>
<p>You can only redirect to the info page.</p>
<?php
exit;
}
}
// 参数缺失的情况
http_response_code (500);
?>
<p>Missing redirect target.</p>
<?php
exit;
?>
代码逻辑拆解:
- 参数校验 :先判断
redirect参数有没有传、是不是空 - 关键字匹配 :核心防护就在第 4 行的
strpos- 函数:
strpos(字符串, 子串) - 作用:查找子串在字符串中第一次出现的位置
!== false表示:只要能找到info.php这几个字就行,不管它在什么位置
- 函数:
- 找到了就直接跳转,没找到就拦截报错
防护的致命缺陷:
strpos 只检查"有没有",不检查"在哪"。只要 URL 里任意位置出现了 info.php 这 8 个字符,就会被判定为合法。
所以:
| Payload | strpos 是否找到 info.php | 结果 |
|---|---|---|
info.php?id=1 |
✅ 开头就是 | ✅ 正常跳转 |
https://evil.com/info.php |
✅ 路径里有 | ✅ 绕过 → 跳外部站点 |
https://evil.com/?x=info.php |
✅ 参数里有 | ✅ 绕过 → 跳外部站点 |
https://evil.com#info.php |
✅ 锚点里有 | ✅ 绕过 → 跳外部站点 |
开发者以为"强制要求包含 info.php = 只能跳站内 info 页面",但实际上只要在恶意 URL 里随便找个地方塞上 info.php 这几个字,就能轻松骗过校验。
一句话总结 High 级别: 子串匹配校验思路太想当然,只验证了"有没有关键字",没验证"是不是真的站内地址",属于典型的"防了但防错了地方"。
5. DVWA Open HTTP Redirect(Impossible)
5.1 源码审计
完整源码逐行解析:
php
<?php
$target = "";
// 双重校验:参数存在 + 参数必须为纯数字
if (array_key_exists ("redirect", $_GET) && is_numeric($_GET['redirect'])) {
// 将参数转为整数,通过switch硬编码白名单映射跳转地址
switch (intval ($_GET['redirect'])) {
case 1:
$target = "info.php?id=1";
break;
case 2:
$target = "info.php?id=2";
break;
case 99:
$target = "https://digi.ninja";
break;
}
// 存在匹配的预设地址才执行跳转
if ($target != "") {
header ("location: " . $target);
exit;
} else {
?>
Unknown redirect target.
<?php
exit;
}
}
?>
Missing redirect target.
三层闭环防御机制
-
输入类型强过滤
is_numeric($_GET['redirect'])限制redirect只能传入数字,彻底杜绝用户自定义URL字符串 ,攻击者无法传入https://evil.com、//evil.com、ftp://xxx等任何恶意跳转Payload。 -
硬编码白名单映射(核心防御)
跳转目标
$target不由用户输入直接赋值,而是通过数字索引匹配后端预先写死的固定地址:
- 传
1→ 固定跳转info.php?id=1 - 传
2→ 固定跳转info.php?id=2 - 传
99→ 固定跳转https://digi.ninja
除此之外所有数字都不会赋值$target,直接提示未知跳转目标。
- 跳转数据源完全可控
最终header("location: " . $target)拼接的变量是后端写死的静态字符串,全程无任何用户可控内容参与URL构造,不存在篡改跳转地址的空间。
漏洞结论
Impossible 级别完全不存在开放重定向漏洞 ,不存在任何绕过方式。即便内置了一条外部域名 https://digi.ninja,该地址也是后端固定写死,攻击者无法修改、替换成任意恶意站点,不会产生钓鱼风险。
5.2 四级对比总结(Low/Medium/High/Impossible)
| 难度 | 防护逻辑 | 核心缺陷 | 是否可绕过 |
|---|---|---|---|
| Low | 无任何校验,直接拼接用户输入跳转 | 完全信任用户可控参数 | 可,任意外部URL直接跳转 |
| Medium | 黑名单正则过滤http:///https:// |
仅拦截网页协议,忽略协议相对URL、ftp等其他协议 | 可,//evil.com、ftp://evil.com绕过 |
| High | 子串匹配,校验URL包含info.php |
仅检查关键字是否存在,不校验关键字位置与站点归属 | 可,恶意URL拼接info.php绕过 |
| Impossible | 数字强限制+硬编码白名单映射 | 无缺陷,用户无法控制跳转目标URL | 不可绕过,彻底封堵漏洞 |
5.3 最终安全修复方案
- 禁止直接使用用户输入拼接跳转地址;
- 使用数字索引+固定白名单映射,由后端预设全部合法跳转地址;
- 若业务必须接收URL参数,采用完整域名白名单校验,而非黑名单/子串匹配;
- 外部域名跳转增加二次确认页面,阻断钓鱼攻击链路。
免责声明
- 本文所有内容仅用于网络安全技术研究与教学演示,所有测试均在本地授权搭建的 DVWA 靶场环境中进行,旨在帮助读者理解漏洞原理与防御机制。
- 请勿将本文涉及的技术与方法用于任何未经授权的真实系统测试。任何利用本文内容进行的非法攻击行为,均与作者无关,由使用者自行承担相应法律责任。
- 网络安全学习请严格遵守《中华人民共和国网络安全法》及相关法律法规,仅在获得明确书面授权的前提下开展安全测试。