最近在研读《白帽子讲web安全》和《Web前端黑客技术揭秘》,为了加深印象,闲暇之时做了一些总结。
下面是书中出现的一些专有词汇:
POC(Proof Of Concept):观点验证程序,运行这个程序就可以得出预期的结果,也就验证了观点。
Payload:有效负载,在病毒代码中实现这个功能的部分。
OWASP:开放式Web应用程序安全项目组织,协助个人、企业和机构来发现和使用可信赖软件。
XSS(Cross Site Script):跨站脚本攻击,想尽一切办法将你的脚本内容在目标网站中的目标用户的浏览器中执行。
如果要调试代码,可以直接在codepen的页面中进行。
一、XSS的几种类型
1)反射型XSS
XSS代码出现在URL中,作为输入提交到服务器,浏览器解析执行。也就是诱使用户点击一个恶意链接,发起攻击。
http://www.xss.com?x=<script>alert('xss')</script>
2)存储型XSS
提交的XSS代码会存储在服务器中(数据库、文件等媒介中),下次请求页面不用再提交XSS代码,典型的场景有博客文章、留言板等。
3)DOM Based XSS
与前面两种不一样的地方是不需要提交到服务器中,可直接在浏览器中执行
//输入http://www.xss.com#alert(1) //执行锚点内容 显示提示框 eval(location.hash.substr(1))
常见的输入输出点可利用下面这些:
//常见的输入点: document.URL document.URLUnencoded document.location(and many of its properties) document.referrer window.location(and many of its properties) //常见的输出点: document.write(…) document.writeln(…) document.body.innerHtml = … //直接修改DOM树: document.forms[0].action = … (and various other collections) document.attachEvent(…) document.create…(…) document.execCommand(…) document.body.…(accessing the DOM through the body object) window.attachEvent(…) //替换document URL: document.location = … (and assigning to location’ s href, host and hostname) document.location.hostname = … document.location.replace(…) document.location.assign(…) document.URL = … window.navigate(…) //打开或修改新窗口: document.open(…) window.open(…) window.location.href = … (and assigning to location’ s href, host and hostname) //直接执行脚本: eval(…) window.execScript(…) window.setInterval(…) window.setTimeout(…)
二、XSS的危害
1)挂马
所谓挂马就是通过各种方法获得网站管理员账号,然后登陆网站后台,网页挂马可通过嵌入iframe实现。
2)盗取用户Cookie
通过“document.cookie”读取Cookie信息,发起劫持,可直接通过加密的Cookie登录凭证登录进用户的账户。
3)DDoS(Distributed Denial of Service)分布式拒绝攻击
在目标浏览器中注入Ajax请求的代码,Ajax请求的响应有同源策略的限制,但请求不会,所以可以同时发起请求攻击。
4)钓鱼攻击
在网页中,伪造真实的登录框,欺骗用户登录时,账号密码就会被盗取。
5)劫持用户Web行为
网站的很多操作是通过HTTP的get或post请求完成的,攻击者可通过代码发起这两种请求,例如构造form、ajax等。
6)XSS Worm(蠕虫)
当被攻击用户查看存在XSS蠕虫代码的内容时,蠕虫触发并开始感染传播。
用户之间发生交互行为的页面,存在存储型XSS,比较容易发起XSS Worm攻击。
三、XSS构造技巧
1)利用字符编码
这里要提一下HTML与JavaScript自解码机制,能够自动执行特定的方式。
1. HTML编码,具体有如下几种形式:
1. 进制编码:&#xH;(十六进制格式)、&#D;(十进制格式),最后的分号(;)可以不要。 2. HTML 实体编码(HtmlEncode),例如“ 、<”等。
<button onclick="document.write('<img src=@ onerror=alert(123) />')">click</button>
2. JavaScript编码,具体有如下几种形式:
1. Unicode 形式:\uH (十六进制)。 2. 普通十六进制:\xH。 3. 纯转义: \' 、 \" 、 \< 、 > 这样在特殊字符之前加 \ 进行转义。
//显示弹出框 document.write("\<img src\=@ onerror=alert\(123\) \/\>")
单纯的输入“<script>”等这些代码可能就会被马上过滤,但是如果再编码一次上面的几种形式,服务器过滤的时候可能就会漏掉。
关于编码的更多信息可以参考《JavaScript字符集编码与解码》。
还可以使用多种编码混淆在一起,更易于绕过服务器过滤。
<!--10进制编码background,16进制编码red--> <div style="background:\72\65\64;">content</div>
3. 标签天生具备HtmlEncode编码,包括标签“title、iframe、noscript、noframes、textarea、xmp、plaintext”。以textarea为例:
<textarea id="textarea">
<div>222</div> </textarea>
//<div>222</div> document.getElementById('textarea').innerHTML
2)base标签
base标签定义页面上所有相对路径标签的host地址。
插入此标签设置域名,然后在远程服务器上定义相同文件名以及路径,劫持当前页面所有使用相对路径的标签。
<base href="http://www.pwstrick.com"/> <!--解析为http://www.pwstrick.com/dist/x.jpg--> <img src='/dist/x.jpg' />
3)window.name的使用
window对象不受同源策略的限制,可通过name属性实现跨域、跨页面传递参数。
window.name="alert(document.cookie)"; //在另外要攻击的页面中注入 就能绕过长度限制执行代码 eval(window.name);
有网友总结了绕过长度限制的技巧,但没找到排版漂亮的版本,只找到百度文档中的一篇,凑合一下看看吧《突破XSS字符数量限制》
4)DOM fuzzing技巧
模糊测试(fuzzing)就是生成特定的数据输入到程序的某个位置,监视程序异常、奔溃、显示结果等。
在前端中可以将代码写到HTML、JavaScript或CSS中都可。
通过在线fuzzing工具Shazzer可以了解更多,不过要注册Twitter账号,我注册成功了但授权没成功,还是不能创建Vector,可惜了。
不过在网站上还是可以看到别人的编写的一些代码。
5)其他
在网上还有个开源小工具XSSProbe,代码简单可供参考。
浏览器有兼容特点,所以可以针对不同的浏览器注入不同代码,浏览器探测可参考《Detecting browsers javascript hacks》
四、XSS防御
1)HttpOnly
浏览器将禁止页面的JS访问带有HttpOnly属性的Cookie。此属性解决的是XSS后的Cookie劫持攻击。
Cookie的使用过程大致如下:
1. 浏览器向服务器发起请求
2. 服务器响应后发送Set-Cookie头(此时可设置HttpOnly),向客户端浏览器写入Cookie
3. 浏览器访问该域下的所有页面都将发送该Cookie(只要Cookie还没过期)
<?php header("Set-Cookie: hidden=value; httpOnly");
2)输入检查
在服务器与客户端添加验证规则,在特定的地方使用特定的规则,例如不匹配“script标签或<、>特殊符号”等。
启用“白名单原则”,可用于标签、属性或事件,只让正常的“a、div”等标签通过。
下面是FindingDOMXSS中对输入点(sources)的匹配规则:
/(location\s*[\[.])|([.\[]\s*["']?\s*(arguments|dialogArguments|innerHTML|write(ln)?
|open(Dialog)?|showModalDialog|cookie|URL|documentURI|baseURI|referrer|
name|opener|parent|top|content|self|frames)\W)|(localStorage|sessionStorage|Database)/
3)输出检查
变量输出到HTML页面时,可以使用编码或转义的方式防御XSS攻击。
针对HTML与JavaScript的编码可通过HtmlEncode和JavaScriptEncode实现,具体的函数内容可参考此处。
在PHP中,可以使用一个开源的项目HTML Purifier实现对XSS的检查。
在FindingDOMXSS中同样给出了输出点(sinks)的匹配规则:
/((src|href|data|location|code|value|action)\s*["'\]]*\s*\+?\s*=)|
((replace|assign|navigate|getResponseHeader|open(Dialog)?|showModalDialog|
eval|evaluate|execCommand|execScript|setTimeout|setInterval)\s*["'\]]*\s*\()/
4)DOM Based XSS防御
DOM Based XSS是直接从“JavaScript”中输出数据到HTML页面里,前面提到的都是从“服务器”中输出。
//x是从服务器中输出的,并且做了JavaScriptEncode操作 var x="\x20\x27onclick\x3dalert\x281\x29\x3b"; //在输出后会变成<a href=" " onclick="alert(1);">test</a>还是能执行点击 document.write("<a href='"+x+">test</a>");
所以要在合适的地方再做一次编码操作,下面是分情况说明:
如果输出到事件或脚本中,则再做一次JavaScriptEncode;如果输出到HTML内容或属性中,就再做一次HtmlEncode。
在OWASP中有一篇《DOM based XSS Prevention Cheat Sheet》,详细记录了发生场景和解决指南。
参考资料: