当前位置: 首页 > WEB安全, 网络安全 > 正文

XSS之防御篇

在上一篇博文《XSS攻击入门》中介绍了XSS相关基础知识。在这篇blog中,将介绍下XSS的相关防御以及修复的知识。

一、HTML Encode

首先,介绍下HTML Encode。XSS之所以会发生, 是因为用户输入的数据变成了代码。 所以我们需要对用户输入的数据进行HTML Encode处理。 将其中的”中括号”, “单引号”,“引号” 之类的特殊字符进行编码。

xss-2

注:HTML Encode 和URL Encode的区别

关于URL 编码是为了符合url的规范。因为在标准的url规范中中文和很多的字符是不允许出现在url中的。所以需要对中文和多数无法显示的字符进行URL编码。

例如一些含有中文的URL会变成这样:
http://www.baidu.com/s?wd=%B2%E2%CA%D4%BA%BA%D7%D6

URL的编码规则是:把所有非字母数字字符都将被替换成百分号(%)后跟两位十六进制数,空格则编码为加号(+)。

二、XSS漏洞检测

方法一:  查看代码,查找关键的变量,   客户端将数据传送给Web 服务端一般通过三种方式 Querystring, Form表单,以及cookie.  例如在ASP的程序中,通过Request对象获取客户端的变量:

<%
strUserCode =  Request.QueryString(“code”);
strUser =  Request.Form(“USER”);
strID =    Request.Cookies(“ID”);
%>

假如变量没有经过htmlEncode处理, 那么这个变量就存在一个XSS漏洞。

方法二: 准备测试脚本;

"/><script>alert(document.cookie)</script><!--
<script>alert(document.cookie)</script><!--
"onclick="alert(document.cookie)

在网页中的Textbox或者其他能输入数据的地方,输入这些测试脚本, 看能不能弹出对话框,能弹出的话说明存在XSS漏洞。在URL中查看有那些变量通过URL把值传给Web服务器, 把这些变量的值退换成我们的测试的脚本。  然后看我们的脚本是否能执行。

方法三:  自动化测试XSS漏洞
现在已经有很多XSS扫描工具了。 实现XSS自动化测试非常简单,只需要用HttpWebRequest类。 把包含xss 测试脚本。发送给Web服务器。 然后查看HttpWebResponse中,我们的XSS测试脚本是否已经注入进去了。

三、XSS的防御

目前主流的浏览器中都内置了一些对抗XSS的措施,比如Firefox的CSP、Noscript扩展,IE8内置的XSS Filter等。但是对于多数网站来说,安全的设计是解决XSS的重要原则。

防御XSS的核心就是对不可信数据进行正确的编码。所以只有在正确的地方使用正确的编码才能消除XSS漏洞。

下面讲解几种 常见 防御XSS漏洞的方案:

1. 使用HttpOnly

对于设置了httponly属性的网页,浏览器将禁止页面的javascript访问cooike的访问。所以,将重要的cookie标记为http only,   这样的话Javascript 中的document.cookie语句就不能获取到cookie了。这可以很好的解决产生XSS后的Cookie劫持问题。

Cooike的产生过程:

A. 浏览器向服务器发起请求,此时没有带Cookie;

B. 服务器返回发送Set-Cookie头,向客户端浏览器写入Cookie;

C. 在该Cookie到期前,浏览器仅向该域下的页面发送Cookie,并且禁止其他js的读写。

HttpOnly在Set-Cookie时被标记,并在http headers里头的Set-Cookie字段中。下面是其简单的使用:

#PHP4
<?php
header("Set-Cookie:sookie1=heheda;httponly");
......
?>
#PHP5
setcookie("abc","test",NULL,NULL,NULL,NULL,TRUE);

2.输入检查

输入检查基本先在用户浏览器中进行。例如, 用户注册时的用户名,当要求只能为字母、数字的组合时,就需要进行严格的过滤。其他的,比如电话、邮件、生日等等,都要有一定 的格式规范。对特殊字符进行编码或者过滤。

当然,在服务端代码也需要进行输入规范的逻辑检查。客户端使用JavaScript检查可以阻挡大部分正常用户的误操作,减小服务端再次验证的资源浪费。

3. 输出检查

(1)不要在页面中插入任何不可信数据

不要往HTML页面中插入任何不可信数据,除非这些数据已经根据下面几条原则进行了编码。XSS漏洞形成的原因有多种,比如有些漏洞发生在HTML标签里,有些发生在HTML标签的属性里,还有的发生在页面的<Script>里,甚至有些还出现在CSS里,再加上不同的浏览器对页面的解析或多或少有些不同,使得有些漏洞只在特定浏览器里才会产生。所以,要遵循“Secure By Default”原则:

<script>…不要在这里直接插入不可信数据…</script>直接插入到SCRIPT标签里 
<!– …不要在这里直接插入不可信数据… –>
插入到HTML注释里
 
<div 不要在这里直接插入不可信数据=”…”></div>
插入到HTML标签的属性名里
 
<div name=”…不要在这里直接插入不可信数据…”></div>
插入到HTML标签的属性值里
 
<不要在这里直接插入不可信数据 href=”…”></a>
作为HTML标签的名字
 
<style>…不要在这里直接插入不可信数据…</style>
直接插入到CSS里

(2)插入不可信数据到HTML标签之间时,进行HTML Entity编码

编码规则见上面的HTML Encode部分。需要对斜杠号( / )编码,因为在进行XSS攻击时,斜杠号对于关闭当前HTML标签非常有用。在OWASP中提供了ESAPI函数库,它提供了一系列非常严格的用于进行各种安全编码的函数。例如:

String encodedContent = ESAPI.encoder().encodeForHTML(request.getParameter(“input”));

(3)插入不可信数据到HTML属性里时,进行HTML属性编码

在往HTML属性(例如width、name、value属性)的值部分(data value)插入不可信数据的时候,应该对数据进行HTML属性编码。编码规则是:除了阿拉伯数字和字母,对其他所有的字符进行编码(该字符的ASCII码小于256)。编码后输出的格式为 &#xHH; (以&#x开头,HH则是指该字符对应的十六进制数字,分号作为结束符)。使用ESAPI提供的函数进行JavaScript编码:

String encodedContent = ESAPI.encoder().encodeForHTMLAttribute(request.getParameter(“input”));

(4)插入不可信数据到SCRIPT里时,进行JavaScript编码

针对动态生成的JavaScript代码,包括脚本部分以及HTML标签的事件处理属性(Event Handler,如onmouseover, onload等)。把这些数据放到使用引号包围起来的值部分(data value)之中,例如:

<script>
    var message = “<%= encodeJavaScript(@INPUT) %>”;
</script>

编码规则是:除了阿拉伯数字和字母,对其他所有的字符进行编码(该字符的ASCII码小于256)。编码后输出的格式为 \xHH (以 \x 开头,HH则是指该字符对应的十六进制数字)。使用ESAPI提供的函数进行JavaScript编码:

String encodedContent = ESAPI.encoder().encodeForJavaScript(request.getParameter(“input”));

(5)插入不可信数据到Style属性里时,进行CSS编码

当需要往Stylesheet,Style标签或者Style属性里插入不可信数据的时候,需要对这些数据进行CSS编码。编码规则是:除了阿拉伯数字和字母,对其他所有的字符进行编码(该字符的ASCII码小于256)。编码后输出的格式为 \HH (以 \ 开头,HH则是指该字符对应的十六进制数字)。使用ESAPI提供的函数进行CSS编码:

String encodedContent = ESAPI.encoder().encodeForCSS(request.getParameter(“input”));

(6)插入不可信数据到HTML URL里时,进行URL编码

当需要往HTML页面中的URL里插入不可信数据的时候,需要对其进行URL编码,如下:

<a href=”http://www.abcd.com?param=…插入不可信数据前,进行URL编码…”> Link Content </a>

编码规则是:除了阿拉伯数字和字母,对其他所有的字符进行编码(该字符的ASCII码小于256)。编码后输出的格式为 %HH (以 % 开头,HH则是指该字符对应的十六进制数字)。使用ESAPI提供的函数进行URL编码:

String encodedContent = ESAPI.encoder().encodeForURL(request.getParameter(“input”));

四、XSS 漏洞修复

原则:不相信的输入数据
注意:  攻击代码不一定在<script></script>中

  1. 将重要的cookie标记为http only,   这样的话Javascript 中的document.cookie语句就不能获取到cookie了.
  2. 只允许用户输入我们期望的数据。 例如: 年龄的textbox中,只允许用户输入数字。 而数字之外的字符都过滤掉。
  3. 对数据进行Html Encode 处理
  4. 过滤或移除特殊的Html标签, 例如: <script>, <iframe> ,  &lt; for <, &gt; for >, &quot for
  5. 过滤JavaScript 事件的标签。例如 “onclick=”, “onfocus” 等等。


这篇博文由 s0nnet 于2016年01月03日发表在 WEB安全, 网络安全 分类下, 通告目前不可用,你可以至底部留下评论。
如无特别说明,计算机技术分享发表的文章均为原创,欢迎大家转载,转载请注明: XSS之防御篇 | 计算机技术分享
关键字: ,

XSS之防御篇:等您坐沙发呢!

发表评论

快捷键:Ctrl+Enter