跨站请求伪造—CSRF

CSRF 介绍

CSRF,是跨站请求伪造(Cross Site Request Forgery)的缩写,是一种劫持受信任用户向服务器发送非预期请求的攻击方式。php

一般状况下,CSRF 攻击是攻击者借助受害者的 Cookie 骗取服务器的信任,在受害者绝不知情的状况下以受害者名义伪造请求发送给受攻击服务器,从而在并未受权的状况下执行在权限保护之下的操做。html

CSRF 攻击示例

这里有一个网站,用户能够看文章,登陆以后能够发评论。前端

若是用户是登陆状态,打开了这样的页面,web

<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <title>csrf攻击</title>
    <meta content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0" name="viewport" />
</head>

<body style="display: none;">
    <form target="myIframe" id="csrf" action="https://www.kkkk1000.com/csrf/data/post_comment.php" metdod="POST">
        <input type="text" name="content" value="csrf攻击" />
    </form>

    <!-- iframe 用来防止页面跳转 -->
    <iframe id="myIframe" name="myIframe"></iframe>

    <script>
        var form = document.querySelector('#csrf');
        form.submit();
    </script>
</body>

</html>

就会自动在文章下发一条评论,这样就算完成了一次 CSRF 攻击。
固然,若是你把这个页面放服务器上,而后作成一个连接,用户点击这个连接,一样能够完成攻击。算法

从图中能够看出,右边和左边的页面是在不一样站点下的,用户打开的右边的空白页,就偷偷提交了一条评论,刷新左边的页面也确实看到了刚刚提交的评论。segmentfault

咱们来看看,此次的攻击是怎么成功的。后端

首先咱们要知道一些关于 Cookie 的知识。浏览器

HTTP Cookie(也叫 Web Cookie或浏览器 Cookie)是服务器发送到用户浏览器并保存在本地的一小块数据,它会在浏览器下次向同一服务器再发起请求时被携带并发送到服务器上。一般,它用于告知服务端两个请求是否来自同一浏览器,如保持用户的登陆状态。Cookie 使基于无状态的 HTTP 协议记录稳定的状态信息成为了可能。

好的,咱们继续往下说。安全

由于用户在网站登陆后,这个网站服务端会在 Cookie 中会放一个凭证,这个凭证是后端用来验证用户身份的。
在发评论的时候,提交评论的请求会带上这个凭证,后端经过判断这个凭证,来确认是哪一个用户。服务器

登陆时,设置 Cookie:

提交评论时,携带 Cookie:

咱们再来看看,发起攻击的页面里的内容。

<body style="display: none;">
    <form target="myIframe" id="csrf" action="https://www.kkkk1000.com/csrf/data/post_comment.php" metdod="POST">
        <input type="text" name="content" value="csrf攻击" />
    </form>

    <!-- iframe 用来防止页面跳转 -->
    <iframe id="myIframe" name="myIframe"></iframe>

    <script>
        var form = document.querySelector('#csrf');
        form.submit();
    </script>
</body>

这些代码的意思就是,当用户点击这个连接,会自动提交 form 表单,而这个表单就是用来提交评论的,提交评论请求须要的参数,在 form 表单中也都已经准备好了,若是用户登陆过网站,Cookie 中存储的用户的凭证,会随着请求一块儿传到服务器端。因此服务器端就会认为这是用户要提交一条评论。

CSRF 特色

  • 攻击通常发起在第三方网站,而不是被攻击的网站。
  • 攻击是利用受害者在被攻击网站的登陆凭证,冒充受害者提交操做,仅仅是“冒用”,而不是直接窃取数据。
  • 攻击者预测出被攻击的网站接口的全部参数,成功伪造请求。

防护方法

SameSite 属性

Cookie 的 SameSite 属性用来限制第三方 Cookie,从而减小安全风险,能够用来防止 CSRF 攻击和用户追踪。

它能够设置三个值。

  • Strict
  • Lax
  • None

Strict

Strict最为严格,彻底禁止第三方 Cookie,跨站点时,任何状况下都不会发送 Cookie。换言之,只有当前网页的 URL 与请求目标一致,才会带上 Cookie。

Set-Cookie: CookieName=CookieValue; SameSite=Strict;

这个规则过于严格,可能形成很是很差的用户体验。好比,当前网页有一个 GitHub 连接,用户点击跳转就不会带有 GitHub 的 Cookie,跳转过去老是未登录状态。

Lax

Lax 规则稍稍放宽,大多数状况也是不发送第三方 Cookie,可是导航到目标网址的 Get 请求除外。

Set-Cookie: CookieName=CookieValue; SameSite=Lax;

Chrome 计划将 Lax 变为默认设置。这时,网站能够选择显式关闭 SameSite 属性,将其设为 None 。不过,前提是必须同时设置 Secure 属性(Cookie 只能经过 HTTPS 协议发送),不然无效。

下面的设置无效:

Set-Cookie: widget_session=abc123; SameSite=None

下面的设置有效:

Set-Cookie: widget_session=abc123; SameSite=None; Secure

要使用 SameSite 属性,前提是用户浏览器支持 SameSite 属性,可使用 caniuse 查看浏览器对于 SameSite 属性的支持。

同源检测

在 HTTP 协议中,每个异步请求都会携带两个 Header ,用于标记来源域名:

  • Origin Header
  • Referer Header

这两个 Header 在浏览器发起请求时,大多数状况会自动带上,而且不能由前端自定义内容。 服务器能够经过解析这两个 Header 中的域名,肯定请求的来源域。

经过校验请求的该字段,咱们能知道请求是不是从本站发出的。咱们能够经过拒绝非本站发出的请求,来避免了 CSRF 攻击。

验证 Origin

若是 Origin 存在,那么直接使用 Origin 中的字段确认来源域名就能够。

可是 Origin 在如下两种状况下并不存在:

  • 一、 IE11同源策略: IE 11 不会在跨站 CORS 请求上添加 Origin 头,Referer 头将仍然是惟一的标识。最根本缘由是由于IE 11对同源的定义和其余浏览器有不一样,有两个主要的区别,能够参考 MDN Same-origin_policy#IE_Exceptions
  • 二、 302重定向: 在302重定向以后 Origin 不包含在重定向的请求中,由于 Origin 可能会被认为是其余来源的敏感信息。对于302重定向的状况来讲都是定向到新的服务器上的 URL ,所以浏览器不想将 Origin 泄漏到新的服务器上。

验证 Referer

若是 Referer 存在,也能够用来确认 HTTP 请求的来源地址。

须要注意的是在如下状况下 Referer 没有或者不可信:

  • 1.IE六、7下使用window.location.href=url进行界面的跳转,会丢失 Referer。
  • 2.IE六、7下使用window.open,也会缺失 Referer。
  • 3.HTTPS 页面跳转到 HTTP 页面,全部浏览器 Referer 都丢失。
  • 4.点击 Flash 上到达另一个网站的时候,Referer 的状况就比较杂乱,不太可信。

总的来讲,同源检测是一个相对简单的防范方法,可以防范绝大多数的 CSRF 攻击,但这并非万无一失的,对于安全性要求较高,或者有较多用户输入内容的网站,咱们就要对关键的接口作额外的防御措施。

验证码

验证码的种类有不少,好比图形验证码,基于人机之间知识差别的验证码,行为式验证码。

CSRF 攻击每每是在用户不知情的状况下成功伪造请求。而验证码会强制用户必须与应用进行交互,才能完成最终请求,并且由于 CSRF 攻击没法获取到验证码,所以一般状况下,验证码可以很好地遏制 CSRF 攻击。
但验证码并非万能的,由于出于用户体验考虑,不能给网站全部的操做都加上验证码。所以,验证码只能做为防护 CSRF 的一种辅助手段,而不能做为最主要的解决方案。

添加 Token 验证

CSRF 攻击之因此可以成功,是由于攻击者能够彻底伪造用户的请求,该请求中全部的用户验证信息都是存在于 Cookie 中,所以攻击者能够在不知道这些验证信息的状况下直接利用用户本身的 Cookie 来经过安全验证。
要抵御 CSRF,关键在于在请求中放入攻击者所不能伪造的信息,而且该信息不存在于 Cookie 之中。能够在 HTTP 请求中以参数的形式加入一个随机产生的 Token,并在服务器端创建一个拦截器来验证这个 Token,若是请求中没有 Token 或者 Token 内容不正确,则认为多是 CSRF 攻击而拒绝该请求。

添加 Token 验证的步骤:

一、服务器将 Token 返回到前端
用户打开页面时,前端发起请求,服务器会返回一个 Token,该 Token 经过加密算法对数据进行加密,通常 Token 都包括随机字符串和时间戳的组合,同时 Token 会存在服务器的 Session 中。以后页面加载完成时,使用 JS 遍历整个 DOM 树,在 DOM 中全部地址是本站的 aform 标签中加入 Token,其余的请求就在编码时手动添加 Token 这个参数。

二、前端发请求时携带这个 Token
对于 GET 请求,Token 将附在请求地址以后,这样 URL 就变成 http://url?token=tokenvalue。 而对于 form 标签发起的 POST 请求来讲,要在 form 的最后加上:

<input type=”hidden” name=”token” value=”tokenvalue”/>

总之,就是前端发请求时把 Token 以参数的形式加入请求中。

三、服务器验证 Token 是否正确
当前端获得了 Token ,再次提交给服务器的时候,服务器须要判断 Token 的有效性,验证过程是先解密 Token,对比加密字符串以及时间戳,若是加密字符串一致且时间未过时,那么这个 Token 就是有效的。

总结

CSRF可以攻击成功的本质是:重要操做的全部参数都是能够被攻击者猜想到的。
因此只要防止攻击者成功的构造一个伪造请求,就能够杜绝攻击了!

案例

希尔顿酒店官网的CSRF漏洞

新浪微博CSRF漏洞

WordPress的CSRF漏洞

参考

HTTP cookies

Cookie 的 SameSite 属性

CSRF漏洞的原理

先后端分离架构下CSRF防护机制

前端安全系列之二:如何防止CSRF攻击?

CSRF 攻击的应对之道

相关文章
相关标签/搜索