Introduction

Intro

跨站点请求伪造-Cross site Request Forgery-CSRF, 又称为”one click attack/session riding”. 攻击者通过诱导受害者执行不当请求来盗取其权限。在这种攻击中,攻击者利用受害者在其他网站上的身份,执行非预期的动作,而受害者通常不会意识到这一行为。

  • CSRF 不仅依赖于 JS, CSRF(高级) 并未打破”同源策略”, 见同源策略. 相反, CSRF 利用同源策略中的 iframe, img 等携带 src 属性的标签来打到跨站点攻击的目的.
  • CSRF 仅仅用于防护跨站点的伪造请求, 利用 session cookie/third-party cookie 在 browser 上的自动填充机制来完成攻击目的. 但是, 如果站点本身拥有 XSS 漏洞, 那么任何 CSRF 防护都是免谈, CSRF 防护仅仅适用于 CSRF 漏洞.
  • CSRF 和 XSS 很多攻击其实都是”损人不利己”的攻击行为, 大部分的攻击都是绕过认证机制, 即借用用户已经认证的 cookie 等来获取权限进行其他危险的操作.

CSRF 的原理, 本质上: 重要危险操作的参数都是可以通过攻击者猜测到. 攻击者在猜测到参数的前提下, 就可以简单的伪造这些参数, 从而达到攻击效果, 如果能够做到”不可预测性原则”, 则在一定程度上提高 CSRF 的防护. 具体见下面的防护实例.

Classify

  • GET: 利用目标网站 GET API 构造请求, 执行某些 evil 操作: 攻击者诱使受害者访问一个链接,该链接携带执行某个动作的 GET 请求。
  • POST: 利用 javascript 的自动表单功能, 自动填充并请求: 诱导用户提交一个表单,该表单发起一个到目标网站的 POST 请求。
  • Flash CSRF: 利用 Flash 发起网络请求
  • CSRF Worm: 类似 XSS Work, 利用社交接口信息(好友列表), 利用 CSRF 漏洞进行大规模的传播
  • 基于 Ajax 的 CSRF: 诱使用户执行脚本,使其发起一个不被预期的 AJAX 请求

CORS

同源策略是一个重要的 web 安全策略,用于限制一个网页中的脚本与不同源的地址进行交互。这意味着,如果你在 A.com 下的网页,你的 JavaScript 不能读取或修改 B.com 的数据。然而,对于 CSRF,同源策略提供了有限的防护。虽然同源策略阻止了一个源向另一个源发送 AJAX 请求并读取响应,但它并不阻止简单地发送请求(如上述的<img>标签例子)。这意味着,即使有同源策略,攻击者仍然可以通过其他手段(如<img>, <form>等)来发起跨站请求。

一般而言, 为了防止 CSRF, 网站后端一般采用 CSRF tokens, 确保一些关键的操作需要一个与会话关联, 不可预测的 token, 从而确保请求是合法的. CSRF 是一个随机生成的唯一标识符,它与用户的会话关联,并在表单提交或 API 请求中作为一个验证参数被传输。Token 的主要目的是确保提交给服务器的请求是来自该站点的,而不是第三方站点.

  1. 生成 csrf token: 用户首次访问一个应用或网页时,服务器会为用户会话生成一个 CSRF Token。
  2. 传输 csrf token 到前端: 生成的 Token 可以嵌入到 HTML 表单中,作为一个隐藏字段,或者可以在加载页面时通过 JavaScript 设置在浏览器的 localStorage 或 sessionStorage
1
2
3
4
5
<form action="/submit" method="post">
<input type="hidden" name="csrf_token" value="generated_token_value" />
<!-- other form fields -->
<input type="submit" value="Submit" />
</form>
  1. 前端发送请求: 提交表单或者发起 AJAX 请求, csrf token 会附带到请求中
  2. 服务器验证: 服务器提取 token 并判断是否与当前的会话匹配, 若成功则继续, 否则直接拒绝

最后, 请注意一点, 即使通过 AJAX 请求获取了另外一个域(攻击服务器)的信息, 但是在返回并准备渲染的时候会被浏览器的同源策略检测并阻止渲染或执行.

Attack

银行交易

整个交易过程:

1
2
3
4
1) WEB-A转账:https://www.mybank.com/Transfer.php?toBankId=11&money=1000
2) 用户在新标签继续浏览WEB-B,此时WEB-A对应的session对应的cookie还是存在
3) 存在危险链接:某个图片链接, https://www.mybank.com/Transfer.php?toBankId=11&money=1000, 其实际上直接跳转到WEB-A,执行扣钱操作
4) 用户点击该链接, CSRF 完成.

整个过程

POST

gmail 曾经有一个 CSRF 漏洞, 攻击者在恶意链接中隐藏了 iframe, 利用参数生成一个 POST 请求并提交, 该请求可以利用 gmail 的 session cookie 创建一条过滤规则, 将用户的所有邮件信息都转发到目的邮箱上. 整个过程:

1
2
3
1) 用户登录gmail, 浏览器获取session cookie
2) 攻击者诱使用户访问恶意链接(iframe)
3) 在这个iframe中, 构造一个post并将请求提交到gmail上, 创建过滤器, 转发邮件

其中链接格式如下:

1
2
// 利用这个 URL 来完成 POST 请求构造
https://www.gnucitizen.org/util/csrf?_method=POST&_encrypt=multipart/form-data&_action=...

CSRF Defeat

Check code

CSRF 的攻击一般都是在用户点击某一个恶意链接, 在”此时无声胜有声”之间默默的执行了某些恶意的操作, 所以在 WEB 前端的一些危险操作上加上一些验证码操作, 提醒用户此时正在执行危险操作, 例如 github 上删除某一个 repository. 但是 check code 又和用户体验相矛盾, 验证码并不能彻底解决该问题.

Referer check

类似”图片防盗链”, 可以利用 Referer 来检查请求是否来自合法的”源”, 从而阻止不在白名单中的请求进行某些危险的操作. 但是服务器并非一定能够获取 Referer, 而且某些用户出现某些考虑, 可能不会携带该头部.

Salt

利用盐值, 每一个用户自身的盐值都是不一样, 并且不是存储在 cookie 中, 从而绕过浏览器自动携带 cookie 的”副作用”操作. 利用盐值, 可以对参数进行加密操作, 从而阻止攻击者猜测到参数. 但是, 利用盐值, 会使 URL 变得极为难读, 并且无法让用户收藏某些 URL(一直在变化), 而且加密的 URL 参数也给其他工作带来困扰.

Token

利用随机生成的 token, 这个随机数必须足够随机, 采用真随机数生产器来产生随机值, 在每一个 tab 中生成一个随机数, 该随机数在 Client/Server 都持有. 其中随机生成的 token, 在每一次提交都会过期, 会重新生成.

PS: 注意该 token 同 authentication token 的区别.