一.跨站脚本攻击(XSS)
1.简介
XSS攻击,通常指黑客通过“HTML注入”篡改了网页,插入了恶意的脚本,从而在用户浏览网页时,控制用户浏览器的一种攻击。
2.类型
XSS根据效果的不同可以分成如下几类。
(1) 反射型XSS
反射型XSS只是简单地把用户输入的数据“反射”给浏览器。也就是说,黑客往往需要诱使用户“点击”一个恶意链接,才能攻击成功。反射型XSS也叫做“非持久型XSS”(Non-persistent XSS)。
(2) 存储型XSS
存储型XSS会把用户输入的数据“存储”在服务器端。这种XSS具有很强的稳定性。
比较常见的一个场景就是,黑客写下一篇包含有恶意JavaScript代码的博客文章,文章发表后,所有访问该博客文章的用户,都会在他们的浏览器中执行这段恶意的JavaScript代码。黑客把恶意的脚本保存到服务器端,所以这种XSS攻击就叫做“存储型XSS”。
(3) DOM Based XSS
DOM Based XSS从效果上来说也是反射型XSS,通过修改页面的DOM节点形成的XSS,称之为DOM Based XSS。
3.XSS Payload
XSS攻击成功后,攻击者能够对用户当前浏览的页面植入恶意脚本,通过恶意脚本,控制用户的浏览器。这些用以完成各种具体功能的恶意脚本,被称为“XSS Payload”。
(1) Cookie劫持
通过XSS攻击,可以完成“Cookie劫持”攻击,直接登录进用户的账户。
因为在当前的Web中,Cookie一般是用户登录的凭证,浏览器发起的所有请求都会自动带上Cookie。如果Cookie没有绑定客户端信息,当攻击者窃取了Cookie后,就可以不用密码登录进用户的账户。
Cookie的“HttpOnly”标识可以防止“Cookie劫持”。
(2) 构造GET与POST请求
能够通过模拟GET、POST请求操作用户的浏览器。
(3) XSS钓鱼
例如利用JavaScript在当前页面上“画出”一个伪造的登录框,当用户在登录框中输入用户名与密码后,其密码将被发送至黑客的服务器上。
(4) 识别用户浏览器
最直接的莫过于通过XSS读取浏览器的UserAgent对象,但是浏览器的UserAgent是可以伪造的。
,另一种识别方法是利用浏览器之间的实现差异来识别。浏览器之间的实现存在差异,不同的浏览器会各自实现一些独特的功能,而同一个浏览器的不同版本之间也可能会有细微差别。所以通过分辨这些浏览器之间的差异,就能准确地判断出浏览器版本,而几乎不会误报。这种方法比读取UserAgent要准确得多。
(5) 识别用户安装的软件
黑客通过判断用户安装的软件,选择对应的浏览器漏洞,最终达到植入木马的目的。
(6) 获取用户的真实IP地址
JavaScript本身并没有提供获取本地IP地址的能力,XSS攻击需要借助第三方软件来完成。比如,客户端安装了Java环境(JRE),那么XSS就可以通过调用Java Applet的接口获取客户端的本地IP地址。
4.XSS攻击平台
- Attack API
- BeEF
- XSS-Proxy
5.XSS Worm (XSS蠕虫)
一般来说,用户之间发生交互行为的页面,如果存在存储型XSS,则比较容易发起XSS Worm攻击。
6.XSS构造技巧
(1) 利用字符编码
(2) 绕过长度限制
攻击者可以利用事件(Event)来缩短所需要的字节数,但利用“事件”能够缩短的字节数是有限的。最好的办法是把XSS Payload写到别处,再通过简短的代码加载这段XSS Payload。
最常用的一个“藏代码”的地方,就是“location.hash”。而且根据HTTP协议,location.hash的内容不会在HTTP包中发送,所以服务器端的Web日志中并不会记录下location.hash里的内容,从而也更好地隐藏了黑客真实的意图。
在某些环境下,可以利用注释符绕过长度限制。
(3) 使用<base>
标签
<base>
标签并不常用,它的作用是定义页面上的所有使用“相对路径”标签的hosting地址。
攻击者如果在页面中插入了<base>
标签,就可以通过在远程服务器上伪造图片、链接或脚本,劫持当前页面中的所有使用“相对路径”的标签。
所以在设计XSS安全方案时,一定要过滤掉这个非常危险的标签。
(4) window.name的妙用
对当前窗口的window.name对象赋值,没有特殊字符的限制。因为window对象是浏览器的窗体,而并非document对象,因此很多时候window对象不受同源策略的限制。攻击者利用这个对象,可以实现跨域、跨页面传递数据。
(5) XSS漏洞
- Apache Expect Header XSS
- Anehta的回旋镖
7.FIash XSS
(1) 尽量禁用Flash
在Flash中是可以嵌入ActionScript脚本,ActionScript是一种非常强大和灵活的脚本,甚至可以使用它发起网络连接,因此应该尽可能地禁止用户能够上传或加载自定义的Flash文件。
由于Flash文件如此危险,所以在实现XSS Filter时,一般都会禁用、等标签。后者甚至可以加载ActiveX控件,能够产生更为严重的后果。
如果网站的应用一定要使用Flash怎么办?一般来说,如果仅仅是视频文件,则要求转码为“flv文件”。flv文件是静态文件,不会产生安全隐患。如果是带动态脚本的Flash,则可以通过Flash的配置参数进行限制。
(2) Flash安全参数
限制Flash动态脚本的最重要的参数是“allowScriptAccess”,这个参数定义了Flash能否与HTML页面进行通信。它有三个可选值:
- always,对与HTML的通信也就是执行JavaScript不做任何限制;
- sameDomain,只允许来自于本域的Flash与Html通信,这是默认值;
- never,绝对禁止Flash与页面通信。
使用always是非常危险的,一般推荐使用never。如果值为sameDomain的话,请务必确保Flash文件不是用户传上来的。
allowNetworking”参数能控制Flash与外部网络进行通信。它有三个可选值:
- all,允许使用所有的网络通信,也是默认值;
- internal, Flash不能与浏览器通信如navigateToURL,但是可以调用其他的API;
- none,禁止任何的网络通信。
一般建议此值设置为none或者internal。设置为all可能带来安全问题。
8.XSS防御
(1) HttpOnIy
浏览器将禁止页面的JavaScript访问带有HttpOnly属性的Cookie。
严格地说,HttpOnly并非为了对抗XSS——HttpOnly解决的是XSS后的Cookie劫持攻击。
(2) 输入检查(XSS Filter)
输入检查的逻辑,必须放在服务器端代码中实现。如果只是在客户端使用JavaScript进行输入检查,是很容易被攻击者绕过的。
目前Web开发的普遍做法,是同时在客户端JavaScript中和服务器端代码中实现相同的输入检查。
(3) 输出检查
一般来说,除了富文本的输出外,在变量输出到HTML页面时,可以使用编码或转义的方式来防御XSS攻击。
安全的编码函数
- HTML:HtmlEncode
- JavaScript:JavascriptEncode,使用JavascriptEncode的变量输出一定要在引号内。
除了HtmlEncode、JavascriptEncode外,还有许多用于各种情况的编码函数,比如XMLEncode(其实现与HtmlEncode类似)、JSONEncode(与JavascriptEncode类似)等。
在“Apache Common Lang”的“StringEscapeUtils”里,提供了许多escape的函数。
(4) 具体实践
XSS的本质还是一种“HTML注入”,用户的数据被当成了HTML代码一部分来执行,从而混淆了原本的语义,产生了新的语义。
想要根治XSS问题,可以列出所有XSS可能发生的场景,再一一解决。
- 在HTML标签中输出:防御方法是对变量使用HtmlEncode。
- 在HTML属性中输出:防御方法也是采用HtmlEncode。
- 在
<script>
标签中输出:在<script>
标签中输出时,首先应该确保输出的变量在引号中,防御时使用JavascriptEncode。 - 在事件中输出:防御时使用JavascriptEncode。
- 在CSS中输出:尽可能禁止用户可控制的变量在
<style>
标签、“HTML标签的style属性”以及“CSS文件”中输出。如果一定有这样的需求,则推荐使用OWASP ESAPI中的encodeForCSS()函数。 - 在地址中输出:一般来说,如果变量是整个URL,则应该先检查变量是否以“http”开头(如果不是则自动添加),以保证不会出现伪协议类的XSS攻击。在此之后,再对变量进行URLEncode,即可保证不会有此类的XSS发生了。
9.处理富文本
在过滤富文本时,“事件”应该被严格禁止,因为“富文本”的展示需求里不应该包括“事件”这种动态效果。而一些危险的标签,比如<iframe>
、<script>
、<base>
、<form>
等,也是应该严格禁止的。
在标签的选择上,应该使用白名单,避免使用黑名单。比如,只允许 <a>
、<img>
、<div>
等比较“安全”的标签存在。
尽可能地禁止用户自定义CSS与style,如果一定要允许用户自定义样式,则只能像过滤“富文本”一样过滤“CSS”。
这需要一个CSS Parser对样式进行智能分析,检查其中是否包含危险代码。Anti-Samy是OWASP上的一个开源项目,也是目前最好的XSS Filter。
10.防御DOM Based XSS
DOM Based XSS是从JavaScript中输出数据到HTML页面里。而前文提到的方法都是针对“从服务器应用直接输出到HTML页面”的XSS漏洞,因此并不适用于DOM Based XSS。
会触发DOM Based XSS的地方有很多,以下几个地方是JavaScript输出到HTML页面的必经之路。
- document.write()
- document.writeln()
- xxx.innerHTML =
- xxx.outerHTML =
- innerHTML.replace
- document.attachEvent()
- window.attachEvent()
- document.location.replace()
- document.location.assign()
需要重点关注这几个地方的参数是否可以被用户控制。
除了服务器端直接输出变量到JavaScript外,还有以下几个地方可能会成为DOM Based XSS的输入点,也需要重点关注。
- 页面中所有的inputs框
- window.location(href、hash等)
- window.name
- document.referrer
- document.cookie
- localstorage
- XMLHttpRequest返回的数据
二.跨站请求伪造(CSRF)
CSRF可以简单定义为:攻击者盗用了玩家身份,以玩家名义发起恶意请求。
1.CSRF进阶
(1) 浏览器的Cookie策略
攻击者伪造的请求之所以能够被服务器验证通过,是因为用户的浏览器成功发送了Cookie的缘故。
浏览器所持有的Cookie分为两种:
- 一种是“Session Cookie”,又称“临时Cookie”;
- 另一种是“Third-party Cookie”,也称为“本地Cookie”。
两者的区别在于,Third-party Cookie是服务器在Set-Cookie时指定了Expire时间,只有到了Expire时间后Cookie才会失效,所以这种Cookie会保存在本地;而Session Cookie则没有指定Expire时间,所以浏览器关闭后,Session Cookie就失效了。
在浏览网站的过程中,若是一个网站设置了Session Cookie,那么在浏览器进程的生命周期内,即使浏览器新打开了Tab页,Session Cookie也都是有效的。
而对于Third-party Cookie,在当前的主流浏览器中,默认会拦截的有:IE 6、IE 7、IE 8、Safari;不会拦截的有:Firefox 2、Firefox 3、Opera、Google Chrome、Android等。
(2) P3P头的副作用
P3P Header是W3C制定的一项关于隐私的标准,全称是The Platform for Privacy Preferences。
P3P头允许跨域访问隐私数据,从而可以跨域Set-Cookie成功。
2.CSRF防御
(1) 验证码
CSRF攻击的过程,往往是在用户不知情的情况下构造了网络请求。而验证码,则强制用户必须与应用进行交互,才能完成最终请求。因此在通常情况下,验证码能够很好地遏制CSRF攻击。
(2) 请求源检测(Referer Check)
Referer Check在互联网中最常见的应用就是“防止图片盗链”。同理,Referer Check也可以被用于检查请求是否来自合法的“源”。
Referer Check的缺陷在于,服务器并非什么时候都能取到Referer。很多用户出于隐私保护的考虑,限制了Referer的发送。
在某些情况下,浏览器也不会发送Referer,比如从HTTPS跳转到HTTP,出于安全的考虑,浏览器也不会发送Referer。
(3) Anti CSRF Token
CSRF为什么能够攻击成功?其本质原因是重要操作的所有参数都是可以被攻击者猜测到的。
在URL中,保持原参数不变,新增一个参数Token,这个Token的值是随机的,不可预测。在实际应用时,Token可以放在用户的Session中,或者浏览器的Cookie中。在使用Token时,要注意Token的保密性和随机性。
在使用Token时,应该尽量把Token放在表单中。把敏感操作由GET改为POST,以form表单(或者AJAX)的形式提交,可以避免Token泄露。
CSRF的Token仅仅用于对抗CSRF攻击,当网站还同时存在XSS漏洞时,这个方案就会变得无效,因为XSS可以模拟客户端浏览器执行任意操作。在XSS攻击下,攻击者完全可以请求页面后,读出页面内容里的Token值,然后再构造出一个合法的请求。这个过程可以称之为XSRF,和CSRF以示区分。
三.点击劫持(ClickJacking)
1.原理
点击劫持是一种视觉上的欺骗手段。攻击者使用一个透明的、不可见的iframe,覆盖在一个网页上,然后诱使用户在该网页上进行操作,此时用户将在不知情的情况下点击透明的iframe页面。通过调整iframe页面的位置,可以诱使用户恰好点击在iframe页面的一些功能性按钮上。
2.攻击类型
- 网页点击劫持
- Flash点击劫持
- 图片覆盖攻击
- 拖拽劫持:“拖拽劫持”的思路是诱使用户从隐藏的不可见iframe中“拖拽”出攻击者希望得到的数据,然后放到攻击者能控制的另外一个页面中,从而窃取数据。
- 触屏劫持
防御方法
针对传统的ClickJacking,一般是通过禁止跨域的iframe来防范。
1.frame busting
通常可以写一段JavaScript代码,以禁止iframe的嵌套。这种方法叫frame busting。
但是frame busting也存在一些缺陷,由于它是用JavaScript写的,控制能力并不是特别强,因此有许多方法可以绕过它。
2.X-Frame-Options
该头部有三个可选的值:
- DENY
- SAMEORIGIN
- ALLOW-FROM origin
当值为DENY时,浏览器会拒绝当前页面加载任何frame页面;若值为SAMEORIGIN,则frame页面的地址只能为同源域名下的页面;若值为ALLOW-FROM,则可以定义允许frame加载的页面地址。