Skip to main content

跨站请求伪造(CSRF)

跨站点请求伪造 CSRF(Cross—Site Request Forgery) 是针对 Web 应用的一种攻击手法。攻击者诱导用户从一个恶意的网站、邮件或博客向用户已经授权正在登陆的网站发起一个非法请求。

过程和原理#

proding.net 是攻击目标网站,攻击者想把所有用户的昵称修改成 “CSRF”(没有实质性危害,恶作剧)。步骤如下:

  1. 攻击者发现通过以下 URI 可以直接修改网站用户的昵称。
POST http://proding.net/user/update
参数:nickname = "CSRF"
  1. 攻击者设计一个场景诱导用户点击自己发布的恶意链接。如攻击者假冒 proding.net 官方向 proding.net 用户发送邮件(假设攻击者已经获取了邮件列表),邮件中包含了被篡改的链接。
//210.23.xxx.xxx  是攻击者的网站,用于向目标网站提交非法请求
//邮件内容
查看安全相关的话题,<a href="http://210.23.xxx.xxx/CSRF.html">请点击这里</a>
//CSRF.html 内容
<form method=POST” action="http://proding.net/user/update">
<input name="nickname" value = "CSRF"></input>
</form>
  1. 用户点击了邮件中的恶意链接,恶意网页被打开,此网页向攻击网站提交修改昵称的请求。
  2. 如果此时用户正好已经登陆目标网站且恶意网站和目标网站用同一款浏览器打开,那么昵称被修改。

    能修改成功的原因是从恶意网站上向目标网站提交的请求中携带了目标网站的 cookies,这个 cookies 含有授权 token。

防御措施#

防范措施的核心就是保证提交请求的源头是合法的,不能伪造。防范措施分为通用自动防御措施个性化防御措施两类,通用自动防御措施是必须的,个性化防御措施做为补充加强根据系统情况任选其一。

  • 通用自动防御措施(必须
    • 依靠标准 HTTP 头信息检查请求来源
  • 个性化防御措施(任选其一)
    • CSRF Token
    • Double Submit Cookie
    • Encrypted Token Pattern
    • Custom Request Headers
    • JWT Authentication(我们的实现中采用的方案

依靠标准 HTTP 头信息检查请求来源#

通过两个标准 HTTP Header 来检查请求来源是否被允许向系统发出请求。如果请求头中没有 Origin 则使用 Referer,如果两者都没有则视为非法请求,终止处理。

  • Origin: 标识发送请求的源头,只包含服务器信息,不包含任何路径信息,如 https://proding.net
  • Referrer: 标识发送请求的页面(URL 或 URI),如 https://proding.net/home.html 或 https://proding.net/home

这种方法的不足是老款的浏览器存在漏洞可以篡改标准 HTTP Header,一个完全依靠浏览器

CSRF Token#

服务器端生成 CSRF token 放入 Session 中,后续请求 token 将作为参数和请求一起发送。这种方法的缺点是需要对页面的每个请求都要改造且难以保证 token 本身的安全。如攻击者在论坛上发布自己网站的地址,由于系统会在这个地址后面加上 token (GEG 方式发送请求),攻击者可以在自己网站上获取这个 token。如果系统采用 POST 方式发送请求,攻击者也可以通过 referrer 获取 token。

Double Submit Cookie#

如果将 CSRF token 存储在 session 中是一个问题。一个替代的方案就是双提交 cookie,即客户端可以将一个随机数同时设置在 cookies 中和请求参数中,服务端验证这两个数是否匹配。

Encrypted Token Pattern#

略。

自定义请求头(Custom Request Headers)#

服务器将用户认证令牌(用户唯一)放到 cookie 中返回给客户端,客户端从 cookie 中读取令牌,在接下来的请求中令牌将作为自定义请求头一起发送给服务端。 服务端比较收到的 cookie 中的令牌值与请求头中的令牌值,如果匹配则视为同源合法请求,否则拒绝请求。这个技术之所以有效,是因为所有浏览器都实现同源策略。只有设置 cookie 的网站的代码才可以访问该站的 cookie,并为该站的请求设置自定义头。

为什么选用自定义请求头方案?#

上面的三个方案都会涉及 UI 层面的修改(拼接请求 URL 等),这样会使前端变的复杂且还会引发其他问题。自定义请求头方案既不会涉及 UI 层面的修改,也无需引入服务端状态(server side state),非常适合基于 REST 服务的应用场景。

同源策略#

同源策略 SOP(Same origin policy) 是浏览器最核心的安全策略之一。它规定只有同源的网页才能:

  • 读取 Cookie、LocalStorage(H5 支持) 和 IndexDB(H5 支持)
  • 获取 DOM。
  • 发送 AJAX 请求。
关于同源的定义#

同源是指协议相同、主机名相同、端口相同。以 http://www.example.com/page1.html 为比较目标:

比较 URL比较结果原因
http://www.example.com/page2.html同源协议相同、主机名相同、端口相同
https://www.example.com/page2.html不同源协议不同
http://www.example.com:8080/page2.html不同源端口不同
http://v1.example.com/page2.html不同源主机名不同(需严格匹配)
http://example.com/page2.html不同源主机名不同(需严格匹配)

JWT 认证#

由于 JWT 认证不使用 cookies,所以天生就对 CSRF 免疫。关于 JWT 请参照本站内 认证