Skip to content
本页目录

CSRF 跨站请求伪造

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

题外话:还有个 SSRFServer-Side Request Forgery)服务器端请求伪造

危害

利用用户登录状态进行操作,如发布留言、盗取用户资金等

攻击类型

  • GET 类型
  • POST 类型
  • 链接类型

GET 类型

假设一个可以支付的请求链接为 http://demo.com/pay?amount=10000&for=hacker,我们将其放入到第三方网站的页面中。

HTML
<img src="http://demo.com/pay?amount=10000&for=hacker" />
<img src="http://demo.com/pay?amount=10000&for=hacker" />

用户在访问了 demo.com 网站并登陆后,又点击进入了这个三方网站,这个网站的内容就是上面的一个图片,而图片的 src 地址就是 demo.com 网站的支付链接,如果后端没做来源 referer 限制,就会进入支付操作。

POST 类型

这种类型的 CSRF 通常使用的是一个隐藏的自动提交表单,如:

HTML
<form action="http://demo.com/pay" method=POST>
  <input type="hidden" name="amount" value="10000" />
  <input type="hidden" name="for" value="hacker" />
</form>

<script> document.forms[0].submit(); </script>
<form action="http://demo.com/pay" method=POST>
  <input type="hidden" name="amount" value="10000" />
  <input type="hidden" name="for" value="hacker" />
</form>

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

原理与 GET 类型一样,进入这个三方页面就会执行,但他是 POST 提交。

链接

需要用户主动点击链接才会触发。一般在论坛中发布的图片中嵌入恶意链接,或者以广告的形式诱导用户中招,攻击者通常会使用比较夸张的词语诱骗用户点击,如:

HTML
<a href="http://demo.com/pay?amount=1000&for=hacker" taget="_blank">重磅消息!!</a>
<a href="http://demo.com/pay?amount=1000&for=hacker" taget="_blank">重磅消息!!</a>

CSRF 特点

  • 攻击一般发起在第三方网站,而不是被攻击的网站。被攻击的网站无法防止攻击发生。
  • 攻击利用受害者在被攻击网站的登录凭证,冒充受害者提交操作;而不是直接窃取数据。
  • 整个过程攻击者并不能获取到受害者的登录凭证,仅仅是“冒用”。
  • 跨站请求可以用各种方式:图片URL、超链接、JSONP、Form 提交等等。部分请求方式可以直接嵌入在第三方论坛、文章中,难以进行追踪。

如何防范

因为 CSRF 通常发生在第三方域名,且攻击者不能获取到用户信息,只是借用他们的登录状态进行请求伪造,所以有以下几种方法:

1. 同源检测

禁止第三方或者非白名单的域名对网站发起请求,服务器可通过请求头的请求来源进行判断:

  • Origin Header
  • Referer Header 标明请求来源域名 缺点:Referer 可以被伪造(比如假设浏览器有某些漏洞导致可以篡改 referer);也会屏蔽搜索引擎的链接

2. CSRF Token

  • 在浏览器向服务器发起请求时,服务器生成一个 CSRF TokenCSRF Token 其实就是服务器生成的随机字符串,然后将该字符串植入到返回的页面中,通常是放到表单的隐藏输入框中,这样能够很好的保护 CSRF Token 不被泄漏;
  • 当浏览器再次发送请求的时候,就需要携带这个 CSRF Token 值一起提交;
  • 服务器验证 CSRF Token 是否一致;从第三方网站发出的请求是无法获取用户页面中的 CSRF Token 值的。

缺点:一般用在前后端不分离场景,每个请求都要添加这个 token,操作繁琐,且在负载均衡时,另一台服务器不存在对应的 session,就无法验证,可通过 jwttoken 生成形式进行改写。

当从 A 网站登录后,会从响应头中返回服务器设置的 Cookie 信息,而如果 Cookie 携带了 SameSite=strict 则表示完全禁用第三方站点请求头携带 Cookie。比如当从 B 网站请求 A 网站接口的时候,浏览器的请求头将不会携带该 Cookie

  • Samesite=Strict,严格模式:这个 Cookie 只能在自己域名下使用 Cookie
  • Samesite=Lax,宽松模式(默认项):假如这个请求是这种请求(改变了当前页面或者打开了新页面)且同时是个 GET 请求,则这个 Cookie 可以作为第三方 Cookie
  1. 当用户访问网站页面是,向请求域名注入一个 Cookie,内容为随机字符串(例如csrfcookie=v8g9e4ksfhw)
  2. 在前端向后端发起请求时,取出Cookie,并添加到URL的参数中(接上例POST https://www.a.com/comment?csrfcookie=v8g9e4ksfhw)
  3. 后端接口验证Cookie中的字段与URL参数中的字段是否一致,不一致则拒绝。

优点:

  • 无需使用 Session,适用面更广,易于实施。
  • Token 储存于客户端中,不会给服务器带来压力。
  • 相对于 Token,实施成本更低,可以在前后端统一拦截校验,而不需要一个个接口和页面添加。

缺点:

  • Cookie 中增加了额外的字段。
  • 如果有其他漏洞(例如XSS),攻击者可以注入 Cookie,那么该防御方式失效。
  • 难以做到子域名的隔离。
  • 为了确保 Cookie 传输安全,采用这种防御方式的最好确保用整站 HTTPS 的方式,如果还没切 HTTPS 的使用这种方式也会有风险。