一、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防御的时候,至少需要将以下字符做转换处理:

        转换前        转换后

           &            &

           <             <

           >             >

           "              "

           '               '

           /              /

        (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攻击,但为什么要将两者分开使用。这是因为浏览器有两套不同的自解码机制。

1、HTML的自解码机制

      浏览器在解析HTML标签属性值内的代码前,会先对下列两种编码进行解码,然后再对属性中的代码进行解析。

(1)、进制解码:&#xH;(十六进制格式)、&#D;(十进制格式)。编码中最后的分号(;)可以不要。且16进制中用来表示10~15的a~f对大小写不敏感

例子:

<iframe src='javascript:alert`1`'></iframe>

也可写成

<iframe src='javascript:alert`1`'></iframe>

(2)、HTML 实体编码

例子:

<input type="button" value="test" onclick="document.write('<img src=@
onerror=alert(123) />')" />

也可写成

<input type="button" value="test" onclick="document.write('<img src=@
onerror=alert(123) />')" />

 

2、JavaScript 自解码机制

(1)、Unicode 形式:\uH(十六进制)。

(2)、普通十六进制:\xH。

(3)、纯转义:\'、\"、\<、\>这样在特殊字符之前加\进行转义。

注:以上三种规则仅在通过JS更改HTML DOM树时才适用( 例如document.write() 
document.getelementbyid().innerhtml=""),直接在<script>标签内使用上述编码,自解码规则不生效。

例子:

<input type="button" id="exec_btn" value="exec" />

<script>

function $(id){return document.getElementById(id);};

$('exec_btn').onclick = function(){

document.write('<img src=@ onerror=alert(123) />');//改代码可执行、可弹窗

//在JS执行前会先将上面这行代码先解码为:document.write('<img src=@ onerror=alert(123)/>');

};

</script>

但如果直接在<script>标签内使用该编码,则自解码机制不生效。

例如:

<script>\u0061\u006c\u0065\u0072\u0074\u0028\u0031\u0032\u0033\u0029</script>

其中上述\u编码内容为alert(123),但该代码并没有更新DOM树,所以不会弹窗。

 

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

1.输出点在HTML标签之间

如<div>输出点</div>

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

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

此处适合使用HtmlEncode,将攻击者输入的<>编码为<> 
使得攻击者无法构造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安全》一书。

关于XSS进阶教程强烈推荐大家看我的另一篇博客,事我很认真,一点点总结出来的,但访问量很少。。。链接如下:

https://blog.csdn.net/sdb5858874/article/details/87913903
<https://blog.csdn.net/sdb5858874/article/details/87913903>