CSRF 攻击和防御原理
CSRF 是跨站点请求伪造 (Cross—Site Request Forgery),存在巨大的危害性,本节讲解 CSRF 攻击和防御的原理。
1. 什么是 CSRF 攻击
CSRF 是英文 Cross Site Request Forgery 的缩写,中文翻译为 “跨站请求伪造”,它是一种挟制用户在当前已登录的 Web 应用程序上执行非本意的操作的攻击方法。
用户使用浏览器登录网站,通过身份验证后,来自该浏览器的请求会得到授权:在服务端可以执行新增数据、修改数据、删除数据等操作。但是,这样的身份验证机制存在一个漏洞:只能保证请求发自某个登录用户的浏览器,却不能保证请求本身是用户自愿发出的。
攻击者利用身份验证漏洞可以挟制用户在当前已登录的 Web 应用程序上执行非本意的操作。
2. CSRF 攻击的过程
2.1 案例简介
本小节通过一个具体的例子,讲解 CSRF 工具的步骤。案例的假设如下:
- 存在一个银行网站,提供在线转账功能;
- 用户登录银行后,才可以使用在线转账功能;
- 银行中存在两个账户:受害者账户、攻击者账户;
- 存在一个恶意网站,当访问该恶意网站时,会自动向银行网站提出转账请求。
如果受害者没有退出银行网站的情况下访问恶意网站,因为受害者已经通过了银行网站的身份验证,因此发出的转账请求会通过银行网站的授权,即攻击者完成了攻击。
2.2 攻击的步骤
发动 CSRF 攻击的步骤如下图所示:
2.2.1 登录
受害者使用用户名、密码登录银行网站。
2.2.2 验证通过
银行网站根据用户名、密码查询数据库,如果匹配,则在 Session 中记录用户已经通过身份验证。
银行网站提供了转账的功能,在实现转账功能时,首先在 Session 中检查是用户是否是登录用户,如果是登录用户,则允许执行转账操作;如果不是登录用户,则不允许执行转账操作。
2.2.3 被诱导
攻击者创办了一个恶意网站,提供一些吸引人的内容(例如:色情、赌博、盗版小说等信息),诱导受害者访问恶意网站。
2.2.4 恶意 HTML
当受害者访问恶意网站时,恶意网站传输给受害者一段恶意的 HTML 代码,恶意的 HTML 代码向银行发起转账请求,代码可能如下:
<form action='http://www.bank.com/transfer' method='post'>
<input type="text" name="name" value="hacker" placeholder="收款账户"/>
<input type="text" name="amount" value="100" placeholder="转账数量"/>
<input type="submit" id="submit" value="转账">
</form>
<script>
var submit = document.getElementById('submit');
submit.click();
</script>
在第 1 行,定义了一个向银行网站提出转账请求的表单,通过 POST 方法向页面 http://www.bank.com/transfer’ 提出转账请求。
在第 2 行,定义了一个名称为 ‘name’、值为 ‘hacker’ 的文本字段,表示转账的收款账户是 ‘hacker’。
在第 3 行,定义了一个名称为 ‘amount’、值为 ‘100’ 的文本字段,表示转账的数量是 100。
在第 8 行和第 9 行,找到提交按钮,模拟提交按钮的 click 操作,实现了自动提交表单。即:用户浏览器访问这段恶意的 HTML 代码后,会自动向银行网站发出转账 100 元的请求。显然,这次转账不是受害者用户的本意,是攻击者伪造的用户请求。
2.2.5 转账
受害者的浏览器收到恶意的 HTML 后,执行恶意的 HTML 中的 Javascript 代码,自动向银行提出了一个转账请求。
银行网站收到转账请求后进行处理,如果受害者没有退出银行网站的登录,此次转账请求可以通过身份验证,可以正常完成转账的功能。
通过以上的 5 个步骤,攻击者成功的挟制了受害者,在当前已登录的银行网站上执行非本意的转账操作。
3. CSRF 防御的方法
在业界目前防御 CSRF 攻击有如下策略:
3.1 验证 HTTP Referer 字段
HTTP Referer 字段简介
在 HTTP 请求头里有个 Referer 字段,用于表明请求的来源地址。以向银行发出转账请求为例,说明 Referer 字段。
1. 用户正常发出转账请求
用户登录银行网站成功后,在网站首页 http://www.bank.com/,存在一个转账按钮;用户通过点击页面上的转账按钮进行转账,向银行发出转账请求
属性 | 描述 |
---|---|
请求的地址 | http://www.bank.com/transfer |
请求的 Referer | http://www.bank.com/ |
可以看出:请求的地址和请求的 Referer 是属于相同的域名。
2. 攻击者通过 CSRF 攻击发出转账请求
如果用户被诱导进入恶意网站 http://www.malicious.com,在恶意网站的页面中向银行发起转账请求,请求的属性如下:
属性 | 描述 |
---|---|
请求的地址 | http://www.bank.com/transfer |
请求的 Referer | http://www.malicious.com/ |
可以看出:请求的地址和请求的 Referer 是属于不同的域名。
3.1.2 验证 HTTP Referer 字段
正常情况下,Referer 字段和请求的地址是位于同一域名下的。如果是 CSRF 攻击发起的请求,那么 Referer 字段和请求的地址就不是同一域名了,因此,服务器通过验证 HTTP Referer 字段就能识别出 CSRF 攻击。
该方法的优点在于:只需要给所有安全敏感的请求统一增加一个拦截器来检查 Referer 的值就可以防御所有的 CSRF 攻击;特别是对于当前现有的系统,不需要改变当前系统的任何已有代码和逻辑,没有风险,非常便捷。
该方法的缺点在于:攻击者能够篡改请求头的 Referer 字段内容,从而欺骗服务器;有可能无法获取 Referer 的值,因为 Referer 值会记录下用户的访问来源,有些用户认为这样会侵犯到他们自己的隐私权,因此,用户自己可以设置浏览器使其在发送请求时不再提供 Referer。
3.2 在请求中添加 Token 并验证
目前业界对 CSRF 的防御,流行的做法是使用一个 Token(Anti CSRF Token)。使用 Token 防御 CSRF 攻击的步骤如下:
- 用户访问某个安全相关的页面,例如银行的转账页面;
- 服务端生成一个随机的 Token,放在用户的 Session 中;
- 在安全相关的页面附带上 Token,返回给客户端;
- 用户提交请求后,服务端获取两个 Token:验证表单中的 Token、用户 Session 中的 Token,如果一致则为合法请求,不一致则识别为 CSRF 攻击。
4. 小结
本节讲解了 CSRF 的概念,如何实施 CSRF 攻击以及如何防御 CSRF 攻击,使用思维导图概括如下: