Node.js中的不安全跳转如何防御详解
Node.js中的不安全跳转如何防御详解
导语:
早年在浏览器大战期间,有远见的Chrome认为要运行现代Web应用,浏览器必须有一个性能非常强劲的Java引擎,于是Google自己开发了一个高性能的开源的Java引擎,名字叫V8。在2009年,Ryan正式推出了基于Java语言和V8引擎的开源Web服务器项目,命名为Node.js。
对于任何web开发人员来说,不安全或未经验证的重定向都是重要的安全考虑因素。Express为重定向提供了本地支持,使它们易于实现和使用。Express是一种保持最低程度规模的灵活Node.js Web应用程序框架,为Web和移动应用程序提供一组强大的
什么是不安全的重定向?
对于任何web开发人员来说,不安全或未经验证的重定向都是重要的安全考虑因素。Express为重定向提供了本地支持,使它们易于实现和使用。然而,Express将执行输入验证的工作留给了开发人员。Express是一种保持最低程度规模的灵活Node.js Web应用程序框架,为Web和移动应用程序提供一组强大的功能。
下面是OWASP.org网站给出的“未经验证的重定向和转发”的定义:
如果web应用程序接受不可信的输入,可能导致web应用程序将请求重定向到不可信输入中包含的URL,则可以进行未经验证的重定向和转发。
重定向通常在登录和身份验证过程中使用,因此可以在登录之前将用户重定向到他们所在的页面。但根据业务需求或应用程序类型而有所不同,也存在其他重定向情况。
为什么要避免重定向?
不验证用户输入的重定向,可以使攻击者具备发起网络钓鱼诈骗的条件,从而窃取用户凭据并执行其他恶意操作。
注意:当在Node.js或Express中实现重定向时,在服务器端执行输入验证很重要。
如果攻击者发现用户没有验证外部用户提供的输入,他们可能会利用这个漏洞在论坛、社交媒体和其他公共场所发布专门设计的链接,让用户点击它。
从表面上看,这些URL看起来合法且对用户来说并无威胁,这是因为所有这些要重定向的URL都包含目标的主机名:
https://example.com/login?url=http://examp1e.com/bad/things
但是,如果服务器端重定向逻辑未验证输入url参数的数据,则用户可能最终会访问黑客所提前设置的网站(examp1e.com),满足攻击的需求!以上只是攻击者如何利用不安全重定向逻辑的一个例子。
不安全重定向例子并将其直接传递到Express res.redirect()方法中。因此,只要用户通过身份验证,Express就会将用户重定向到输入或提供的URL。
var express = require('express');
var port = process.env.PORT || 3000;
var app = express();
app.get('/login', function (req, res, next) {
if(req.session.isAuthenticated()) {
res.redirect(req.query.url);
}
});
app.get('/account', function (req, res, next) {
res.send('Account page');
});
app.get('/profile', function (req, res, next) {
res.send('Profile page');
});
app.listen(port, function() {
console.log('Server listening on port ' + port);
});
输入验证有助于防止不安全的重定向
通常,最好避免在代码中使用重定向和转发。如果你一定需要在代码中使用重定向,则首选的方法是使用映射到特定目标的预定义输入,这被称为白名单方法。以下就是实现这种方法的一个具体样本步骤:
1.baseHostname会确保任何重定向都将用户保留在研究人员的主机上;
2.redirectMapping是一个对象,它将预定义的输入(例如,传递给url paramer的内容)映射到服务器上的特定路径;
3.validateRedirect()方法会判断预定义的输入是否存在,如果它们存在,则返回要重定向的适当路径;
4.研究人员修改了/login逻辑,然后将baseHostname+redirectPath变量连接在一起,这就避免了任何用户提供的输入内容直接传递到Express res.redirect()方法中;
5.最后,研究人员使用encodeURI()方法作为额外的安全保证,确保连接字符串的URI部分被正确编码,以允许干净的重定向。
//Configure your whitelist
var baseHostname = "https://example.com";
var redirectMapping = {
'account': '/account',
'profile': '/profile'
}
//Create a function to validate whitelist
function validateRedirect(key) {
if(key in redirectMapping) {
return redirectMapping[key];
}else{
return false;
}
}
app.get('/login', function (req, res, next) {
if(req.session.isAuthenticated()) {
redirectPath = validateRedirect(req.query.url);
if(redirectPath) {
res.redirect(encodeURI(baseHostname + redirectPath));
}else{
res.send('Not a valid redirect!');
}
}
});
其他重定向场景
在某些情况下,将每个组合列入白名单是不切实际的,不过有些安全平台仍然希望重定向用户并将其保留在域内某些边界内。当外部提供的值遵循特定模式(例如16个字符的字母数字字符串)时,最好这样做。字母数字字符串是理想的,因为它们不包含任何可能引入其他攻击的特殊字符,例如目录/路径遍历(依赖于诸如…和向后/向前斜杠之类的字符)。
例如,安全平台可能希望在用户登录后将其重定向回电子商务网站上的特定产品。由于电子商务网站对每种产品都有唯一的字母数字值,因此安全平台可以通过始终根据RegEx白名单验证外部输入来实现安全重定向。在本文所讲的样本在,研究者用的是productId变量。
//Configure your whitelist
var baseHostname = "https://example.com";
app.get('/login', function (req, res, next) {
productId = (req.query.productId || '');
whitelistRegEx = /^[a-zA-Z0-9]{16}$/;
if(productId) {
//Validate the productId is alphanumeric and exactly 16 characters
if(whitelistRegEx.test(productId)) {
res.redirect(encodeURI(baseHostname + '/item/' + productId));
}else{
//The productId did not meet the RegEx whitelist, so return an error
res.send('Invalid product ID');
}
}else{
//No productId was provided, so redirect to home page
res.redirect('/');
}
});
最后,安全平台发出警告,警告用户他们正在被自动重定向是值得重视的。如果安全平台有意将用户重定向到域外,则可能需要在流程中创建一个中间页面,该页面会发出如下警告,并包含用户要重定向到的URL。
注:本文是以Hailstone为例进行讲解的,Hailstone是一个应用程序安全平台,它有查找代码中的漏洞功能。
本文翻译自:https://blog.hailstone.io/how-to-prevent-unsafe-redirects-in-node-js
同步发布: https://www.geek-share.com/detail/2751082347.html
Node.js中的不安全跳转如何防御详解的更多相关文章
- node.js 包教不包会 (Windows版详解)
针对@alsotang 的新手入门教程 https://github.com/alsotang/node-lessons ,详解该教程在Windows中的实践,包括博主在实践过程中遇到的问题及解决方案 ...
- Js中JSON.stringify()与JSON.parse()与eval()详解及使用案例
JSON(JavaScript Object Notation)是一种轻量级的数据交换格式.因为采用独立于语言的文本格式,也使用了类似于C语言家族的习惯,拥有了这些特性使使JSON称为理想的数据交换语 ...
- 【转】JS中setTimeout和setInterval的最大延时值详解
前言 JavaScript提供定时执行代码的功能,叫做定时器(timer),主要由setTimeout()和setInterval()这两个函数来完成.而这篇文中主要给大家介绍的是关于JS中setTi ...
- js中的事件委托(事件代理)详解
本文转载:https://www.cnblogs.com/liugang-vip/p/5616484.html#!comments js中的事件冒泡.事件委托是js 中一些需要注意的小知识点,这里结合 ...
- 【转】Js中的window.parent ,window.top,window.self 详解
[转自]http://blog.csdn.net/zdwzzu2006/article/details/6047632 在应用有frameset或者iframe的页面时,parent是父窗口,top是 ...
- Js中的window.parent ,window.top,window.self 详解
在应用有frameset或者iframe的页面时,parent是父窗口,top是最顶级父窗口(有的窗口中套了好几层frameset或者iframe),self是当前窗口, opener是用open方法 ...
- Js中的window.parent ,window.top,window.self详解
在应用有frameset或者iframe的页面时,parent是父窗口,top是最顶级父窗口(有的窗口中套了好几层frameset或者iframe),self是当前窗口, opener是用open方法 ...
- JS中的call、apply、bind方法详解
bind 是返回对应函数,便于稍后调用:apply .call 则是立即调用 . apply.call 在 javascript 中,call 和 apply 都是为了改变某个函数运行时的上下文(co ...
- js中的bool值转换及"&&" 、"||"、 "!!"详解
bool值转换 数据类型 bool值转化 undefined undefined 转化为 false Object null 转化为false,其他为 true Boolean false 转化为 f ...
随机推荐
- python闭包&装饰器&偏函数
什么是闭包? 首先还得从基本概念说起,什么是闭包呢?来看下维基上的解释: 在计算机科学中,闭包(Closure)是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数.这个被引用的 ...
- oracle-2_dblink的创建和使用
一.创建dblink 1.查询创建dblink表 SELECT * FROM DBA_DB_LINKS; ); BEGIN SELECT COUNT(*) INTO I FROM DBA_DB_LIN ...
- Java 实现斐波那契数列
public class Fibonacci { private static int getFibo(int i) { if (i == 1 || i == 2) return 1; else re ...
- x86 分页机制——虚拟地址到物理地址寻址
x86下的分页机制有一个特点:PAE模式 PAE模式 物理地址扩展,是基于x86 的服务器的一种功能,它使运行 Windows Server 2003, Enterprise Edition 和 Wi ...
- oracle 表 视图 存储过程 序列 job
table 表 --delete table drop table Test1; -- Create table create table TEST1 ( ID NUMBER, T_N ...
- 初识EMC
EMC,即电磁兼容,是指设备在预期的电磁环境中,能按设计要求正常抵抗电磁干扰的能力.其主要包含3个方面:电磁干扰(EMI),电磁抗扰(EMS)与静电放电抗扰(ESD). 电磁干扰的方式可以大概分为传导 ...
- POSIX多线程—线程基本概念
http://blog.csdn.net/livelylittlefish/article/details/7957007 作者:阿波链接:http://blog.csdn.net/livelylit ...
- BZOJ1033:[ZJOI2008]杀蚂蚁antbuster(模拟)
Description 最近,佳佳迷上了一款好玩的小游戏:antbuster.游戏规则非常简单:在一张地图上,左上角是蚂蚁窝,右 下角是蛋糕,蚂蚁会源源不断地从窝里爬出来,试图把蛋糕搬回蚂蚁窝.而你的 ...
- LA 4256 商人
题目链接:https://vjudge.net/contest/160916#problem/B 题意:给一个无向图,和一个序列:要求,在这个序列中,两两相连的两个数相同,或者,在无向图中相邻:(n& ...
- 使用Sleep方法延迟时间
实现效果: 关键知识:(线程的定义) 实现代码: private void Form1_Load(object sender, EventArgs e) { Thread show = new Thr ...