防止xss注入
xss攻击从发生的时间段来看,主要有两种防御方式,第一种是防止xss注入,第二种则是在xss注入之后防止恶意程序运行。
关于如何防止xss注入这个问题,最常见或者说最好用的办法就是过滤。
1.客户端过滤(反射型xss,DOM型xss)####
反射性XSS:发出请求时,XSS代码出现在URL里,作为输入提交到服务器端,服务器端解析后响应,XSS代码随浏览器一起传回给浏览器,最后浏览器解析执行XSS代码。这个过程像一次反射,故叫反射性XSS。
DOM型XSS:不经过反射,直接在客户端代码里执行的恶意代码,这个过程是反射型XSS
比如在URL里带上<script>标签(反射型)
http://123.207.46.233/?from=<script>alert(1)</script>
或者博客里的回复直接插入DOM节点(DOM型)
<li>恶意代码</li>
这些情况发生xss注入,所以应该对任何来源的数据保持怀疑的态度,都要先过滤,再运行。
最简单的过滤便是将这种恶意标签转义,
function html_encode(str) {
if (!str) {
return str;
}
return str.replace(/[<>&"']/g, (all) => {
return {
'<': '<',
'>': '>',
'&': '&',
'"': '"'
"'": '''
}[all]
});
}
但是上面的代码不能解决所有的问题,比如有人不用明文,全部使用Unicode的方式,你如这种
u0026u006cu0074u003bu0073u0063u0072u0069u0070u0074u0026u0067u0074u003bu0061u006cu0065u0072u0074u0028u00
26u0023u0033u0039u003bu6211u662fu0078u0073u0073uff0cu4f60u6709u9ebbu70e6u4e86u0026u0023u0033u0039u003bu00
29u0026u006cu0074u003bu002fu0073u0063u0072u0069u0070u0074u0026u0067u0074u003b
这种恶意代码就会突破上面转义的防守,所以字符编码应该统一设置
假如是富文本编辑,那么上面的过滤方式是没有什么效果的。这时比较安全的方法是建立白名单,对所有的标签属性进行检测,标签的可以属性进行正则匹配,只要不在白名单里的,一律过滤掉。
var cheerio = require('cheerio');
var xssFilter = function (html) {
if (!html) {
return '';
}
var $ = cheerio.load(html);
var whiteList = {
'img': ['src'],
'font': ['color', 'size'],
'a': ['href']
}
$('*').each(function (index, elem) {
let name = elem.name;
if(!whiteList[name]) {
$(elem).remove();
return;
}
for (var attr in elem.attribs) {
if (whiteList[name].indexOf(attr) === -1) {
$(elem).attr(attr, null);
}
}
})
}
实际代码更为复杂,还要对属性的值进行检测(上面代码没有写),比如对图片的src,a标签的href内容进行白名单匹配
2.服务端过滤(储存型XSS)
加入恶意代码直接发送到了服务器,而服务器不加过滤就储存了起来,这就对所以使用这个服务器的客户端造成了潜在的威胁,一旦客户端出现了过滤不完全的情况,就会受到威胁,所以服务器在代码入库之前也应该进行防止XSS的过滤。
而对于如何在XSS注入之后进行防御,有这几种想法。
1.对于代理劫持之后嵌套iframe的行为,进行windows网页的重定向
2.对所有事件在捕获阶段进行监听,若有异常,立即移除事件的目标阶段(对于mousemove类的事件需要进行优化)
3.白名单对src过滤(或者重写setAttribute,添加过滤事件,建立拦截上报)
4.利用MutationObserver进行静态脚本拦截
具体代码和实现方法可以查看详细介绍如何在注入后防御的这两篇文章
http://www.cnblogs.com/yangxiaolan/p/5784266.html
http://fex.baidu.com/blog/2014/06/xss-frontend-firewall-1/
防止CSRF
CSRF主要是服务端多做防御,现在主流的防御方式有着几种
1.验证码
验证码被认为是对抗csrf攻击最简洁有效的防御方法。csrf攻击往往是在用户不知情的情况下构造了网络请求,而验证码则是强制用户与应用进行交互来完成最终的请求。但是出于对用户体验的考虑,网站不会在所有的操作上都加上验证码,所以这只能作为一种辅助手段,而不是最终的解决方案。
2.referer check
referer是http请求header中的一个参数,允许客户端指定请求url的源资源地址。所以referer check可以用于检查请求是否来自合法的“源”。常见的互联网应用,页面与页面之间都具有一定的逻辑关系,这使得每个正常清请求的referer都具有一定的规律。举个栗子,比如进行发表博客的操作,在提交发表博客的表单时,referer的值必然是编辑博客所载的页面,如果不是这个页面甚至不是这个网站的域那么极有可能是csrf攻击。这种防御手段的缺陷在于,服务器不是任何时候都能取得referer,所以这只能作为一种监控手段而无法作为主要的防御手段。
3.Anti CSRF Token
现在业界针对csrf防御的一致做法是使用token。csrf能够成功的本质原因是攻击者可以猜出请求中的所有参数和参数值,所以才能成功地构造一个伪造的请求。所以直观的解决方案是:把参数加密,或者使用一些随机数从而让攻击者无法猜测到参数值,目前业界通用的方案就是使用AntiCSRFToken。那么针对我们开头所说的那个栗子?,保持原有参数不变,新增一个参数token,这个token的值是随机的,不可预测:''blog.balabala.com/manager/entry.do?m=delete&id=12345&token=[random(seed)]'' 。在实际应用中,token同时放在表单和session(或者cookie)中,在提交请求的时候服务器只需要验证表单中的token和用户session(或者cookie)中的token是否一致从而判断这个请求是否合法