一、HttpOnly属性         

       为Cookie中的关键值设置httponly属性,众所周知,大部分XSS(跨站脚本攻击)的目的都是通过浏览器的同源策略,来获取用户Cookie,从而冒充用户登陆系统的。

       如果为Cookie中用于用户认证的关键值设置httponly属性,浏览器将会禁止js通过同源策略访问cookie中设有httponly属性的信息,因此以劫持用户认证cookie为目的XSS攻击将会失败。

        但和明显,只为cookie中的值设置Httponly是不够的,因为XSS攻击并不是只能获取用户COOKIE,它还可以窃取用户浏览器信息,模拟用户身份执行操作等等。(具体内容详见:《白帽子讲Web安全》)

 

二、对用户输入进行检查——XSS filter

       XSS filter是在用户提交数据时获取变量,并进行XSS 过滤的。此时的XSS filter只对用户输入数据进行XSS检查,并没有结合渲染页面的HTML代码。

       所以针对XSS filter需要强调两点:

       1.XSS filter对语境的理解并不完整(比如:无法针对输出点位置进行合适的XSS过滤。所以有时可能会造成遗漏、破坏原有语义等后果)

       2.XSS filter是在URL服务器解码之前生效的,所以要考虑URL编码绕过的问题。(比如XSS filter过滤了<script>标签,但如果用户输入的是经过URL编码后的<script>标签:%3C%73%63%72%69%70%74%3E,这样就饶过了原本的XSS filter检测)

 

三、对用户输出进行检查——安全的编码函数

        (1)HtmlEncode

一般来说,在进行XSS防御的时候,至少需要将以下字符做转换处理:

        转换前        转换后

           &            &amp;

           <             &lt;

           >             &gt;

           "              &quot;

           '               &#x27;

           /              &#x2F;

        (2)JavascriptEncode

javascriptEncode的编码方式和HtmlEncode有所不同,它使用  \  对特殊字符进行转义。

常用的JavaScript编码函数为:escapeJavascript()

该函数的功能为:将 ‘    ”  <   >   \   &   #  这些个危险字符进行转义。

举一个《白帽子讲Web安全》里的例子

var x=1;alert(2);

var y="1;alert(2)";

JS环境内,第一行的弹窗代码会被执行,第二行则会是安全的,即使攻击者想要尝试闭合",输入的"也会被JavaScript编码转义为\"。这样攻击者相要绕过"的封锁也会十分苦难。

不过这里需要注意

1.如果页面使用的是GBK编码,可能会被攻击者利用类似宽字节注入的方式绕过。比如

2.用户的输出如果是在标签内,则要求JavascriptEncode的变量输出点一定要被引号包裹。

如果用户输出点太多,导致开发人员无法针对性的对用户输出进行编码、转义。则可以使用更严格的Javascriptencode函数,使用函数将除了数字、字母之外的所有字符通通都以"\xHH"的方式进行16进制编码。

接下来需要介绍一个很重要的东西,是我当天总结的重中之重!!!!!!

相信很多初学者会和我一样,非常好奇为什么会有Htmlencode和JavaScriptEncode两种编码方式,从功能上来看都可以抵御XSS攻击,但为什么要将两者分开使用。原因如下!!!

因为浏览器在收到服务器返回的数据时,会先对JS环境内的字符串进行htmlencode解码,之后再执行js(此处的JS环境包括所有可以执行js代码的地方,比如<script>标签之间,on事件等等)。

所以,如果在js环境内使用htmlencode编码的方式对输出字符做XSS防御处理,当字符串发送到浏览器后,浏览器会在执行JS脚本之前,先对脚本中的字符串进行html解码。也是因为这一机制,导致通过Htmlencode编码的XSS防御在JS环境内的失效,Javascriptencode也就应用而生。

四、针对不同的输出点使用合适的编码方式

1.输出点在HTML标签之间

如<div>输出点</div>

攻击者如果想要构造XSS语句并执行,需要构造一个能执行脚本的环境。示例如下:

<div><script>alert`1`</script></div>

此处适合使用HtmlEncode,将攻击者输入的<>编码为&lt;&gt; 
使得攻击者无法构造JS环境,导致XSS失败。

 

2.输出点在HTML属性中输出

<div id='111' name="输出点"></div>

普通攻击者尝试的方法为将name属性的双引号闭合,然后再构造xss语句。

<div id='111' name=" "><script>alert`1`</script><""></div>

此处同样推荐使用HtmlEncode

 

3.输出点在<script>标签中

在<script>标签中输出时,首先应该确保输出的变量在引号中,例如
<script> var x="输出点"</script>

此处的防御思想是:使攻击者无法闭合标签,导致无论输入什么参数都会被浏览器当作字符串处理。

此处应使用JavascriptEncode。
 

4.在事件中输出
   在事件中输出和在<script>标签中类似
<a href=# onclick="funcA('输出点')">超链接</a>

攻击方法举例:

<a href=# onclick="funcA('');alert`1`;//')">超链接</a>

 

5.在CSS中输出

因为对CSS不太熟悉,所以此部分暂不介绍。

但根据白帽子一书中的介绍,推荐使用  encodeForCSS()函数

 

6.在地址栏中输出

在地址栏中的输出比较复杂,但总结起来相较于前面有两点需要注意:

(1).输出点在路径或者参数中。
<a href="http://www.test.com/test=输出点">test</a>

攻击者可按照如下方式构造payload

<a href="http://www.test.com/?test=" onclick=alert(1) "">test</a>

此处的防御方法为使用URLEncode,是代码变成下面这样

<a href="http://www.test.com/?test=%22%20%6F%6E%63%6C%69%63%6B%3D%61%6C%65%72%74%28%31%29%20%22">test</a>

 

(2).输出点为整个URL

<a href="输出点">test</a>

此时就不能单纯的使用URLEncode来抵御XSS攻击了,因为协议和域名部分是不能够进行URL编码的,不然会改变原有的语意。

此处攻击者可能会构造伪协议实施攻击

<a href="javascript:alert(1);">test</a>

能被攻击者利用的伪协议有:javascript,vbscript,dataURL

dataURL这个伪协议是Mozila所支持的,能够将一段代码写在URL里

<a href="data:text/html;base64,PHNjcmlwdD5hbGVydGAxYDwvc2NyaXB0Pg==">test</a>

这段base64字符串解码后就是<script>alert`1`</script>

所以此处的防御方法应为:
<script> <style> <a>等标签的src和href属性必须以白名单的方式强制为   http://或https://开头,并且不能有10进制和16进制编码的字符串。(此处的做法是防止攻击者使用伪协议进行XSS攻击)

 

7.DOM型XSS的防御

如果用户的输出点在<script>之间时,须先进行一次JavaScriptEncode,在通过document.write等方式输出到HTML页面时,如果输出点为事件或者脚本,须再进行一次JavaScriptEncode,如果输出点为HTML的内容或者属性,则需要做一次Htmlencode。

 

五、总结
输出到HTML标签内或者之间,需使用HtmlEncode编码进行防御。

输出到JavaScript标签内或者之间,需要进行JavaScriptencode来进行防御。

抵御DOM型XSS,当使用document.write等方法向HTML页面内输入内容时,如过输出点在JS环境内就要再进行一次JavascriptEncode,如果输出点在HTML标签内,则再进行一次HtmlEncode

     

以上内容大部分参考《白帽子讲Web安全》一书。

11-17 22:19