前端安全知识以及防范

基础

XSS就是让浏览器执行想插入的js。那么如何发现这些漏洞呢?只要有输入和输出的地方都伴随着漏洞的产生,下面介绍基础的XSS漏洞分析。
XSS攻击并非一个<sc+ript+>al+ert('xs+s漏洞')</script>(这里请看源码)语句就可以检测。

<script>alert('xss漏洞')</script>
  • XSS初级测试(反射型XSS):
    反射型XSS需要欺骗用户点击才能触发XSS代码。

  • 输入框是否过滤<>’”/等字符,输入框中输入这些字符后提交,查看网页源码中这四个字符有没有被过滤;

  • 在输入框或者url的参数中输入<img onerror=alert(1) src=1>后,如果出现界面错误,那就提BUG吧;

  • 使用eval()函数,该函数执行js代码,输入框输入或者url参数等于eval("alert('Hello world')”),是否能够执行。

  • XSS中级测试:

  • 宽字节注入漏洞,GB系列这些编码格式只有两个字节,引起的安全问题是吃一个ASCII字符的现象像一个<input type=“text” value=“”> 的语句,我们要做的是闭合双引号(%22),但是如果value输入%22的话就会被转义为%5C%22,如果输入%C0%22 /><script>alert(1)</script>的话,过滤器发现%22加入转义(%5C),然而%C0吃掉了%5C,这样就闭合了前面的双引号。

  • 存储型XSS,和前面的反射型XSS不同,是将XSS代码提交服务器中并存储下来,其他人在访问能拿到该字段的页面就会触发XSS代码执行。我找到了一个乌云上淘宝宝贝详情的存储型XSS。

  • 测试建议:

  • 必须对所以交互的输入字符、http请求头部变量、cookie变量等检测字符和html关键字段;

  • 前端或者客户端做了过滤还不够,服务端也要进行过滤;

  • 为了防止存储型XSS产生,对存入数据库的字段不光要在输入字符时进行过滤和检测,还要在数据库字段输出到页面时进行过滤和检测;

  • 网上已有的XSS代码:XSS代码;

  • 乌云上很多XSS漏洞的真实例子,大家测试之余可以去搜来看看,乌云网站。

深入

XSS攻击的本质是执行代码,根据代码在页面中的执行环境可分为3种:

1.存储型XSS
用户访问正常的URL,触发代码执行。
大部分情况是由于过滤不完全或未转码,直接渲染到页面中,导致代码执行。

2.DOM型XSS
用户访问正常的URL,触发代码执行。
前端人员经常把数据埋在Dom节点中,然后通过JS代码获取内容,渲染,然后插入到页面中,导致代码被执行。

3.反射型XSS
用户访问经过特殊构造的URL,触发代码执行.
常通过垃圾邮件传播,邮件内容大多是具有诱惑性的内容,引诱点击。QQ被盗后,空间说说等经常出现不明链接等等。

存储型XSS漏洞根据代码执行位置不同,又可分为:

1.HTML存储型

发表文章,填写资料,留言等数据提交到后台,过滤不全,在用户访问页面的时候,恶意内容渲染到页面中,导致攻击。

2.CSS存储型
常见于淘宝店铺装修,网页换肤,背景图等,这些地方都需要用户提交CSS样式,甚至引入外部JS,如果对输入没有做严格的校验,直接渲染到页面,极易产生安全隐患

淘宝商品详情页的评论记录,交易记录都曾被非法篡改。

攻击的方式多种多样,CSS支持unicode,很多漏洞直接采用编码的方式绕过安全漏洞。

<div style="width:expression(if(!window.x){alert(1);window.x=1})"></div>
<link rel=stylesheet href=data:,*%7bx:expression(if(!window.x)%7balert(1);window.x=1%7d)%7d />
<div style="width:expression(if(!window.x){alert(1);window.x=1})"></div>
<table background="javascript:alert(/xss/)"></table>'

3.JS存储型

这种比较少见,有时候会前端会使用eval,jQuery.globalEval,前者在代码中比较常见,1688这边,去年安全部集中处理过一批这些漏洞。

用户一般难以直接输入JS代码,但有时候,前端开发人员会要求将数据直接转成JS代码,放入到页面中,方便获取,如果内容未经过安全处理,攻击者就会尝试中断正常的代码逻辑,插入攻击代码。

Dom型XSS攻击

'''
前端开发者,经常将数据存放在Dom节点,在某个时候,获取节点的数据,然后插入到页面中,插入到页面时,常使用jQuery('body').html('<script>alert(3)</script>') 操作,导致代码被执行。

反射型XSS攻击

用户访问经过特殊构造的URL,URL参数中会携带攻击代码。

现在我们假设一种攻击场景:私信

  1. 攻击者A,利用私信功能向用户B发送私信,私信内容存在攻击代码(JS)
  2. 用户浏览私信,浏览的过程中,JS代码在同域名下,毫无顾忌地执行,相当于开发方自己的代码
  3. 用户B成为受害者
  4. 攻击代码可以将受害者B的其它私信提交到自己的内容收集平台
  5. 攻击代码自动与好友发送私信,私信内容与上述一样。从而产生新的受害者。。。。
  6. 如此循环

可以看到,用户B的私密消息,完全被暴露。
很多网站产品会让用户填写个人资料,身份证,姓名等等,一旦发生此类攻击,用户的信息也就被泄露了。
目前网站依赖token做CSRF校验,其有效的前提是不存在XSS漏洞,token不会泄露。

防御

在编写代码的时候,尽量站在攻击者角度去编写代码。

其实记住两点就行:

  1. 不要信任用户输入的任何数据

  2. 输入、输出过滤

作为防御方,我们尽量够做的其实很有限,不同的场景,可能有不同的漏洞产生,提高自身的安全意识,编写安全代码是我们目前能够做的。

举个小例子,判断一个URL是否是1688域名,在前端提交的时候会做判断,后台也会做判断。
正则可能如下:
/http://.*.1688.com/i
大家可以思考一下这个正则有问题吗? 前端可能写对了,后台开发人员呢?
在攻击发生时,往往是多个类型XSS互相利用,最后产生较大的安全问题。还有就是新技术的应用,比如NodeJs,在安全方面的处理还是不够,这种在线上也存在相同的问题。目前也有新的CSP策略,在高级浏览器(IE10,)中可以起到一定的安全防御作用,但是就当前环境来说,低版本浏览器,我们还没法放弃。
一些例子
2011年,新浪微博XSS蠕虫事件:攻击者利用广场的一个反射性XSS URL,自动发送微博、私信,私信内容又带有该XSS URL,导致病毒式传播。
09年twitter也发生过类似事件。
乌云平台也有很多此类例子,可以搜索关键词XSS

  1. 安全平台自己也有漏洞 ,rank 10,http://wooyun.org/bugs/wooyun-2010-059832
  2. 阿里云账号泄露 ,rank 20, http://wooyun.org/bugs/wooyun-2010-054102
  3. 腾讯微博 http://www.wooyun.org/bugs/wooyun-2010-020167
  4. 百度贴吧 http://www.wooyun.org/bugs/wooyun-2010-053221 太多了。。。。。。
    有时候,漏洞的危害性可能不是很大,但是极易引起用户反弹,公关问题,。

实践 -- show me the code

前端XSS

前端XSS往往由于前端层面用innerHTML或者$('#id').html('...')方法时,没有对用户输入的内容和正常的HTML代码进行隔离,从而让黑客可以轻松获取JS执行权限。

那么,标准的前端逻辑应该怎么写?

$('#id').html('![](test.jpg)');

如果我们使用的是模板,例如handbar,由于handbar默认会进行转义,因此默认即是安全的:


理论上,我们建议能使用模板的场景尽量使用模板,能为我们节省大量的代码量,并且同时也能保证我们代码不会出现XSS漏洞。
对于使用underscore的同学,请留意下默认的是不转义的,例如:
hello: <%= name %>
如果需要转义,请务必使用:
hello: <%- name %>
注:我们对underscore进行了改造,将这两个标识进行了翻转,经过改造后,也符合了默认转义的原则。

成果

在这之外,我们还有什么手段解决前端XSS问题呢?

jQuery目前已经无孔不入,几乎找不着没有使用jQuery的业务场景。

我们的方案是在外部对jQuery进行了hack,将所有html代码进行安全过滤,以实现前端防火墙的功能。

过滤逻辑如下:将所有js代码过滤为无效代码, 例如:

'''
<img src="" onerror="alert(1)"> <script>alert(1)</script>
'''

会替换为:

'''
<img src="" onerror0="alert(1)"> <script0>alert(1)</script>
'''

经过此过滤,XSS就再也无法猖狂了!

并且,此方案还有1个优点,由于此方案是全站底层进行防火部署,因此过滤算法可以随时进行优化升级,以解决今后出现新的XSS漏洞。

不过,此方案并非没有缺陷。由于此方案屏蔽了所有的JS代码,因此对于旧逻辑中所有HTML和JS混合的场景都需要进行改造。

但是,根据实际部署过程来看,这种混合场景占比非常非常少。

我如何部署?

security.js

'''js
(function (win) {
var security = {}; // 初始事件正则
var objOnEvents = {};
var reAllEvents; // init all events
var doc = document;
var arrDoms = [window, doc.createElement("form")];
try {
arrDoms.push(doc.createElement("img"));
arrDoms.push(doc.createElement("iframe"));
arrDoms.push(doc.createElement("object"));
arrDoms.push(doc.createElement("embed"));
arrDoms.push(doc.createElement("audio"));
} catch (e) {
}
var dom;
var key;
for (var i = 0, c = arrDoms.length; i < c; i++) {
dom = arrDoms[i];
for (key in dom) {
if (/^on/.test(key)) {
objOnEvents[key.substring(2)] = 1;
}
}
}
var arrAllEvents = [];
for (key in objOnEvents) {
arrAllEvents.push(key);
}
if (arrAllEvents.length > 0) {
reAllEvents = new RegExp('(['"\\s\\/]on(?:' + arrAllEvents.join('|') + '))\\s*=', 'ig'); } else { reAllEvents = /(['"\s/]on(\w+))\s=/ig;
} // HTML转义
security.encodeHTML = function (str) {
return String(str).replace(/&/g, '&').replace(/"/g, '"').replace(/'/g, ''').replace(//g, '').replace(/</g, '<').replace(/>/g, '>');
}; // 过滤html中可能引发XSS的代码
security.htmlFilter = function (str, args) {
var reBadTags = /<(script|link|frame)([^\w])/ig;
var reBadAttrs = /['"\s\/](srcdoc)\s*=/ig; var reBadSrc = /[\'"\s/]src\s
=\s['"]?\s(javascript:|data\s:\stext/html)/ig;
str = String(str); // 过滤script & link...
str = str.replace(reBadTags, '<$10$2'); // 过滤on事件
str = str.replace(reAllEvents, '$10='); // 过滤srcdoc属性
str = str.replace(reBadAttrs, ' $10='); // 过滤危险src: javascript: data:
str = str.replace(reBadSrc, ' src0="');
return str;
}; // hack jQuery
security.hookJquery = function ($) {
if ($ && !$.fn.rawHtml) { // 1. html->rawHtml
$.fn.rawHtml = $.fn.html;
$.fn.html = function (value) {
var args = Array.prototype.slice.call(arguments);
if (typeof value === 'string' && $.htmlFilter) {
args[0] = security.htmlFilter(value, arguments);
}
return $.fn.rawHtml.apply(this, args);
};
}
};
win.security = security;
})(window);
'''

test.html

''' html
<div id="test"></div>
<script type="text/javascript" src="js/jquery-1.10.2.js"></script>
<script type="text/javascript" src="security.js"></script>
<script type="text/javascript">
security.hookJquery($); $.htmlFilter = true; $('#test').html('<img src="" onerror="alert(1)">')
</script>

框架底层可以直接将jQuery进行hook,但是具体过滤逻辑是否开启取决于$.htmlFilter是否打开。

在部署过程中,请务必要保证业务代码全部改造为纯HTML的情况下才能开启开关,否则会造成线上故障

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,898评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,401评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,058评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,539评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,382评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,319评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,706评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,370评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,664评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,715评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,476评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,326评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,730评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,003评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,275评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,683评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,877评论 2 335

推荐阅读更多精彩内容