Skip to main content

什么是 CSRF?

是什么

CSRF 跨站请求伪造:攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求。利用受害者在被攻击网站已经获取的注册凭证,绕过后台的用户验证,达到冒充用户对被攻击的网站执行某项操作的目的。

CSRF 攻击攻击原理及过程

  • 用户 C 打开浏览器,访问受信任网站 A,输入用户名和密码请求登录网站 A;
  • 在用户信息通过验证后,网站 A 产生 Cookie 信息并返回给浏览器,此时用户登录网站 A 成功,可以正常发送请求到网站 A;
  • 用户未退出网站 A 之前,在同一浏览器中,打开一个 TAB 页访问网站 B;
  • 网站 B 接收到用户请求后,返回一些攻击性代码,并发出一个请求要求访问第三方站点 A;
  • 浏览器在接收到这些攻击性代码后,根据网站 B 的请求,在用户不知情的情况下携带 Cookie 信息,向网站 A 发出请求。网站 A 并不知道该请求其实是由 B 发起的,所以会根据用户 C 的 Cookie 信息以 C 的权限处理该请求,导致来自网站 B 的恶意代码被执行

怎么解决

  - **CSRF 攻击之所以能够成功:**是因为黑客可以完全伪造用户的请求,该请求中所有的用户验证信息都是存在于 cookie 中,因此黑客可以在不知道这些验证信息的情况下直接利用用户自己的 cookie 来通过安全验证

所以解决办法是:在请求中放入黑客所不能伪造的信息,并且该信息不存在于 cookie 之中 - 增加验证码 只有通过验证的请求才算合法。但是这种方案拥有两个局限性,一个是增加开发成本,另外一个是降低用户体验。 - cookies 设置 sameSite - CSRF 的伪造请求的域名不是网站 A,那么通过限制 cookies 不被其他域名网站使用,来达到防御的目的 - 方法:cookies 设置 sameSite 属性的值为 strict,这样只有同源网站的请求才会带上 cookies。但是此方案有浏览器兼容问题。

    - **验证 HTTP Referer 字段**
- 根据 HTTP 协议,在 HTTP 头中有一个字段叫 Referer,它记录了该 HTTP 请求的来源地址,因此我们可以限制不信任的请求来源。
- 但是鉴于Referer 本身是可以修改的,Referer 可以作为一种辅助手段,来判断请求的来源是否是安全的。
- **方法:**后端可以根据HTTP请求头的`referer`来判断请求是否来自可信任网站
- **token:在 HTTP 头中自定义属性并验证 / 在请求地址中添加 token 并验证**
- **方法:**服务端随机生成token,保存在服务端session中,同时保存到客户端中,客户端发送请求时,把token带到HTTP请求头或参数中,服务端接收到请求,验证请求中的token与session中的是否一致。

一般的情况下,点开一个诱导你的链接,黑客会在你不知情的时候做哪些事情呢

  1. 自动发起 Get 请求

黑客网页里面可能有一段这样的代码 👇

<img src="http://bank.example/withdraw?amount=10000&for=hacker" >

在受害者访问含有这个 img 的页面后,浏览器会自动向http://bank.example/withdraw?account=xiaoming&amount=10000&for=hacker发出一次HTTP请求。

bank.example 就会收到包含受害者登录信息的一次跨域请求。

  1. 自动发起 POST 请求

黑客网页中有一个表单,自动提交的表单 👇

<form action="http://bank.example/withdraw" method=POST>

<input type="hidden" name="account" value="xiaoming" />

<input type="hidden" name="amount" value="10000" />

<input type="hidden" name="for" value="hacker" />

</form>

<script> document.forms[0].submit(); </script>

访问该页面后,表单会自动提交,相当于模拟用户完成了一次 POST 操作。

同样也会携带相应的用户 cookie 信息,让服务器误以为是一个正常的用户在操作,让各种恶意的操作变为可能。

  1. 引诱用户点击链接

这种需要诱导用户去点击链接才会触发,这类的情况比如在论坛中发布照片,照片中嵌入了恶意链接,或者是以广告的形式去诱导,比如:

<a href="http://test.com/csrf/withdraw.php?amount=1000&for=hacker" taget="_blank">

重磅消息!!!

点击后,自动发送 get 请求,接下来和自动发 GET 请求部分同理。

以上三种情况,就是 CSRF 攻击原理,跟 XSS 对比的话,CSRF 攻击并不需要将恶意代码注入 HTML 中,而是跳转新的页面,利用「服务器的验证漏洞」和「用户之前的登录状态」来模拟用户进行操作

「防护策略」

其实我们可以想到,黑客只能借助受害者的cookie骗取服务器的信任,但是黑客并不能凭借拿到「cookie」,也看不到 「cookie」的内容。另外,对于服务器返回的结果,由于浏览器「同源策略」的限制,黑客也无法进行解析。

这就告诉我们,我们要保护的对象是那些可以直接产生数据改变的服务,而对于读取数据的服务,则不需要进行CSRF的保护。而保护的关键,是 「在请求中放入黑客所不能伪造的信息」

「用户操作限制——验证码机制」

方法:添加验证码来识别是不是用户主动去发起这个请求,由于一定强度的验证码机器无法识别,因此危险网站不能伪造一个完整的请求。

「1. 验证来源站点」

在服务器端验证请求来源的站点,由于大量的 CSRF 攻击来自第三方站点,因此服务器跨域禁止来自第三方站点的请求,主要通过 HTTP 请求头中的两个 Header

Origin Header

Referer Header

这两个 Header 在浏览器发起请求时,大多数情况会自动带上,并且不能由前端自定义内容。

服务器可以通过解析这两个 Header 中的域名,确定请求的来源域。

其中,「Origin」只包含域名信息,而「Referer」包含了具体的 URL 路径。

在某些情况下,这两者都是可以伪造的,通过 AJax 中自定义请求头即可,安全性略差。

「2. 利用 Cookie 的 SameSite 属性」

可以看看 MDN 对此的解释

SameSite 可以设置为三个值,Strict、Lax 和 None。

在 Strict 模式下,浏览器完全禁止第三方请求携带 Cookie。比如请求 sanyuan.com 网站只能在 sanyuan.com 域名当中请求才能携带 Cookie,在其他网站请求都不能。

在 Lax 模式,就宽松一点了,但是只能在 get 方法提交表单况或者 a 标签发送 get 请求的情况下可以携带 Cookie,其他情况均不能。

在 None 模式下,Cookie 将在所有上下文中发送,即允许跨域发送。

「3. CSRF Token」

前面讲到 CSRF 的另一个特征是,攻击者无法直接窃取到用户的信息(Cookie,Header,网站内容等),仅仅是冒用 Cookie 中的信息。

那么我们可以使用 Token,在不涉及 XSS 的前提下,一般黑客很难拿到 Token。

可以看看这篇文章,将了 Token 是怎么操作的彻底理解 cookie,session,token

Token(令牌)做为 Web 领域验证身份是一个不错的选择,当然了,JWT 有兴趣的也可以去了解一下。

Token 步骤如下:

「第一步:将 CSRF Token 输出到页面中」

首先,用户打开页面的时候,服务器需要给这个用户生成一个 Token,该 Token 通过加密算法对数据进行加密,一般 Token 都包括随机字符串和时间戳的组合,显然在提交时 Token 不能再放在 Cookie 中了(XSS 可能会获取 Cookie),否则又会被攻击者冒用。因此,为了安全起见 Token 最好还是存在服务器的 Session 中,之后在每次页面加载时,使用 JS 遍历整个 DOM 树,对于 DOM 中所有的 a 和 form 标签后加入 Token。这样可以解决大部分的请求,但是对于在页面加载之后动态生成的 HTML 代码,这种方法就没有作用,还需要程序员在编码时手动添加

参考文章: