防止nodejs中的开放重定向攻击安全吗?
Posted
技术标签:
【中文标题】防止nodejs中的开放重定向攻击安全吗?【英文标题】:Is preventing open redirects attack in nodejs secure? 【发布时间】:2016-10-06 17:10:29 【问题描述】:我正在尝试防止开放重定向攻击。请查看以下代码并检查安全性:
var = require('url');
// http://example.com/login?redirect=http://example.com/dashboard
app.route('/login', function (req, res, next)
var redirect = req.query.redirect,
paths = url.parse(redirect);
if (paths.host !== req.headers.host)
return next(new Error('Open redirect attack detected'));
return res.redirect(redirect);
);
是否足以防止开放重定向攻击还是我应该添加其他任何东西?
【问题讨论】:
可以更容易使用redirect=dashboard
,然后在服务器上使用res.redirect('http://example.com/' + req.query.redirect);
这样重定向将永远不会离开您的服务器。
谢谢。如何不在res.redirect
中硬编码http://example.com/
,而是使用req.host
或类似的东西?
res.redirect('http://' + req.host + '/' + req.query.redirect);
您可以创建此答案并为每个人描述您的方法
【参考方案1】:
CWE-601: URL Redirection to Untrusted Site ('Open Redirect')
Open Redirect
的描述:
http 参数可能包含 URL 值,并可能导致 Web 应用程序将请求重定向到指定的 URL。通过将 URL 值修改为恶意站点,攻击者可能会成功发起网络钓鱼诈骗并窃取用户凭据。由于修改后链接中的服务器名称与原始站点相同,因此网络钓鱼尝试具有更可信的外观。
input validation
策略防止开放重定向攻击的建议:
假设所有输入都是恶意的。使用“接受已知良好”的输入验证策略,即使用严格符合规范的可接受输入的白名单。拒绝任何不严格符合规范的输入,或将其转换为符合规范的输入。 不要仅仅依靠寻找恶意或格式错误的输入(即,不要依靠黑名单)。黑名单可能会遗漏至少一个不受欢迎的输入,尤其是在代码环境发生变化的情况下。这可以为攻击者提供足够的空间来绕过预期的验证。但是,黑名单可用于检测潜在攻击或确定哪些输入格式错误以至于应该彻底拒绝它们。 使用批准的 URL 或域的白名单来进行重定向。
使用req.headers.host
、req.host
或req.hostname
是不安全的,因为req.headers
可以被伪造(例如,HTTP 请求具有自定义的Host
标头来访问用以下代码编写的快速应用程序)
var url = require('url');
app.get('/login', function (req, res, next)
var redirect = req.query.redirect,
targetUrl = url.parse(redirect);
console.log('req.headers.host: [%s]', req.headers.host);
console.log('req.host: [%s]', req.host);
console.log('req.hostname: [%s]', req.hostname);
if (targetUrl.host != req.headers.host)
return next(new Error('Open redirect attack detected'));
return res.redirect(redirect);
);
使用curl
发出请求:
$ curl -H 'Host: malicious.example.com' 'http://localhost:3012/login?redirect=http://malicious.example.com' -i
HTTP/1.1 302 Found
X-Powered-By: Express
Location: http://malicious.example.com
Vary: Accept
Content-Type: text/plain; charset=utf-8
Content-Length: 54
Date: Mon, 13 Jun 2016 06:30:55 GMT
Connection: keep-alive
$ #server output
req.headers.host: [malicious.example.com]
req.host: [malicious.example.com]
req.hostname: [malicious.example.com]
我建议你使用白名单来验证输入,示例代码如下:
const WHITELIST_TO_REDIRECT = new Set(["localhost:3012", "www.realdomain.com"]);
app.get('/login', function (req, res, next)
var redirect = req.query.redirect,
targetUrl = url.parse(redirect);
console.log("req.hostname: [%s]", req.hostname);
console.log("url.host: [%s]", targetUrl.host);
if (!WHITELIST_TO_REDIRECT.has(targetUrl.host))
return next(new Error('Open redirect attack detected'));
return res.redirect(redirect);
);
【讨论】:
感谢您的回答。是否可以不使用白名单但通过正则表达式进行一些验证? 当然。正则表达式还表示whitelist
的范围,当白名单不太长时,硬编码白名单会更清楚。
如果主机头是由用户的浏览器伪造的,那么该用户就有更大的安全问题。虽然这是一种明智的做法,但从安全的角度来看,我无法通过检查 Host
标头看到提供了什么。
我同意你的看法。但是,如果主机头是用户浏览器伪造的,这可能吗?【参考方案2】:
在这种情况下,我会使用HMAC。这将允许登录控制器验证 redirect
参数是否由知道密钥的人生成。
当您生成“登录”网址时,您会将redirect
参数的 HMAC 摘要与重定向参数本身一起添加到网址中。
登录处理程序可以使用 HMAC 来确保 redirect
参数是由知道 HMAC 密钥的受信任服务器生成的,从而防止开放式重定向攻击。
例如
var crypto = require('crypto');
var secretKey = 'change-me';
var loginUrl = 'http://example.com/login'
// called to work out where to redirect to for login
function getLoginUrl(redirectBackUrl)
var sig = crypto.createHmac('sha1', secretKey)
.update(redirectBackUrl)
.digest('hex');
return loginUrl
+ '?redirect='
+ encodeURIComponent(redirectBackUrl)
+'&sig=' + sig;
// called by the login function to ensure that the
// redirect parameter is valid
function isRedirectUrlValid(url, sig)
var expectedSig
= crypto.createHmac('sha1', secretKey)
.update(url)
.digest('hex');
return expectedSig === sig;
【讨论】:
以上是关于防止nodejs中的开放重定向攻击安全吗?的主要内容,如果未能解决你的问题,请参考以下文章
Web安全相关:开放重定向(Open Redirection)
Web安全相关:开放重定向(Open Redirection)