未验证的重定向
威胁描述
未验证的重定向是一种攻击方式,攻击者通过操纵URL参数或表单数据,将用户重定向到恶意网站。这种攻击通常用于钓鱼攻击,诱导用户输入敏感信息(如用户名、密码、信用卡号等)。未验证的重定向可能导致用户信任的网站被用来传播恶意链接,从而导致身份盗窃、财务损失和声誉损害。
工作原理
- 应用程序存在一个重定向功能,使用用户输入来确定重定向的目标URL
- 攻击者构造包含恶意URL的参数或表单数据
- 应用程序未对重定向目标进行适当验证或白名单检查
- 用户被重定向到恶意网站,可能遭受进一步攻击
示例代码
1. 简单的未验证重定向
// 前端代码
const redirectUrl = new URLSearchParams(window.location.search).get('redirect');
if (redirectUrl) {
window.location.href = redirectUrl;
}
// 攻击者构造的URL
https://trusted-website.com/login?redirect=https://malicious-website.com/phishing
// 用户登录后被重定向到恶意网站
2. 表单中的未验证重定向
<!-- 前端表单 -->
<form action="/login" method="POST">
<input type="text" name="username" placeholder="用户名">
<input type="password" name="password" placeholder="密码">
<input type="hidden" name="redirect" value="https://malicious-website.com/phishing">
<button type="submit">登录</button>
</form>
<!-- 不安全的后端代码(Node.js) -->
app.post('/login', (req, res) => {
// 验证用户名和密码
if (authenticated) {
const redirectUrl = req.body.redirect || '/dashboard';
res.redirect(redirectUrl);
}
});
3. 跳转链接中的未验证重定向
<!-- 不安全的跳转链接 -->
<a href="/redirect?url=https://malicious-website.com/phishing">点击继续</a>
<!-- 后端代码 -->
app.get('/redirect', (req, res) => {
const url = req.query.url;
res.redirect(url);
});
防御措施
1. 前端验证
在前端对重定向URL进行基本验证,确保其合法性:
// 验证重定向URL是否属于可信域
function validateRedirectUrl(url) {
const trustedDomains = ['trusted-website.com', 'api.trusted-website.com'];
try {
const parsedUrl = new URL(url);
return trustedDomains.includes(parsedUrl.hostname);
} catch (e) {
return false;
}
}
// 安全的重定向处理
const redirectUrl = new URLSearchParams(window.location.search).get('redirect');
if (redirectUrl && validateRedirectUrl(redirectUrl)) {
window.location.href = redirectUrl;
} else {
window.location.href = '/dashboard'; // 默认重定向
}
2. 后端白名单验证
在后端对重定向目标进行严格的白名单验证:
// 后端白名单验证(Node.js)
const allowedRedirects = ['/dashboard', '/profile', '/settings'];
app.get('/redirect', (req, res) => {
const url = req.query.url;
// 验证URL是否在白名单中
if (allowedRedirects.includes(url)) {
res.redirect(url);
} else {
// 处理无效重定向
res.redirect('/dashboard');
}
});
3. 使用相对路径
尽量使用相对路径而非绝对路径进行重定向:
// 安全的相对路径重定向
res.redirect('/dashboard');
// 而非绝对路径
// res.redirect('https://trusted-website.com/dashboard');
4. 避免传递完整URL
避免在URL参数中传递完整URL,而是使用标识符:
// 使用标识符而非完整URL
const redirectMap = {
'dashboard': '/dashboard',
'profile': '/profile',
'settings': '/settings'
};
app.get('/redirect', (req, res) => {
const target = req.query.target;
const redirectUrl = redirectMap[target] || '/dashboard';
res.redirect(redirectUrl);
});
最佳实践
- 对所有重定向目标进行严格的白名单验证
- 尽量使用相对路径而非绝对路径进行重定向
- 避免在URL参数中传递完整URL,使用标识符代替
- 在前端和后端都实施重定向验证,但以后端验证为主
- 教育用户识别钓鱼网站的特征(如URL异常、拼写错误等)
- 实施内容安全策略(CSP),限制重定向的来源
- 定期进行安全测试,包括未验证重定向测试
- 保持Web应用程序和依赖库的更新,以防止已知漏洞被利用
- 对敏感操作后的重定向进行额外验证,确保安全性