CSRF攻击与Django防范

什么是CSRF

CSRF,全称 Cross Site Request Forgery,跨站请求伪造,是一种欺骗受害用户在已登陆的web应用上按照攻击者的指令执行恶意操做的攻击行为。攻击的影响范围取决于受害用户所拥有的的权限,由于攻击者是依赖用户在当前会话中的鉴权进行恶意操做的。html

CSRF是如何工做的

CSRF仅在用户已被受权的状况下才能生效。经过CSRF,攻击者能够绕开web应用的鉴权机制,进而利用受害者的用户权限对web应用进行恶意操做。好比网上银行等场景。web

下面是CSRF攻击的两个主要组成部分:django

  1. 第一步是欺骗用户点击一个连接或者加载一个页面,一般是利用一些社交手段诱使用户点击一个恶意连接。
  2. 第二部是在这个恶意连接中,经过用户的浏览器向web应用发起一个伪造的请求。这个伪造请求看起来是合法的,可是携带的是攻击者伪造的数据。与此同时,浏览器会在请求中带上与该web应用关联的cookie。由于cookie中包含了用户以前登录的token鉴权信息,在用户没有登出或者token没有过时以前,该鉴权信息是持续有效的。这样攻击者就能够依靠该cookie直接获取到用户的权限进行恶意操做了。

(HTTP session和cookie机制请见cookie与session的区别以及在Django中的实现)api

CSRF攻击实际上就是利用了HTTP会话的cookie机制,由于浏览器会在每次请求中都带上与web应用关联的cookie。浏览器

CSRF攻击示例

假设这是一个合法的url,用于向指定的User用户转帐1000块钱。bash

http://example.com/transfer?amount=1000&account=User
复制代码

当用户发送该请求时,若是用户已经登陆过web应用且鉴权经过,则浏览器会在请求中自动携带包含鉴权信息的cookie,这样用户进行转帐时就不须要再次进行登陆验证;若是用户还未登陆鉴权,则会须要先进行登陆鉴权,而后浏览器才能进一步携带cookie信息发起转帐请求。 web应用须要拿到转帐请求中携带的cookie用于验证用户信息,才能得知是要从哪一个用户的帐户中将钱转出。cookie

1. 使用GET请求进行攻击

若是web应用能够接受GET请求,那攻击者只须要在恶意连接的html中加入以下的代码,经过img标签自动向web应用伪造一个转帐请求。利用浏览器自动携带cookie的机制,就能够从用户帐户中盗走1000块钱。session

<img src="http://example.com/transfer?amount=1000&account=Fred" />
复制代码

该场景中的web应用除了存在CSRF漏洞之外,还有一个问题:任何的GET请求都应该是“只读“的,不该该对数据产生任何影响。因此该场景中的web应用设计是不合理的。post

2. 使用POST请求进行攻击

下面是使用POST进行攻击的html表单代码网站

<h1>You Are a Winner!</h1>
<form action="http://example.com/api/account" method="post">
 <input type="hidden" name="Transaction" value="withdraw" />
 <input type="hidden" name="Amount" value="1000" />
 <input type="submit" value="Click Me"/>
</form>
复制代码

试想以下攻击场景:

  1. 用户登陆web应用example.com,并进行了鉴权。
  2. web应用对用户进行受权,并在响应中携带了包含鉴权token的cookie。
  3. 用户在没有登出的状况下,又打开了一个包含上述html表单的恶意页面。(注意该表单中的action是将请求发送到存在漏洞的web应用,而不是恶意页面自己,这就是Cross-Site,跨站请求)
  4. 用户点击恶意页面中的"Click Me"按钮提交,浏览器在请求中携带cookie发给web应用。
  5. 伪造的请求利用携带的cookie经过了web应用的鉴权,取得了用户所拥有的的权限,进行恶意操做。

值得注意的是,SSL是没法防御CSRF攻击的。由于攻击者只须要在伪造请求中指定https访问便可。

防范CSRF攻击

最经常使用的CSRF防范机制就是使用csrf token机制。

  1. csrf token基于一个随机生成的秘钥secret,并经过salt hash方式加密生成csrftoken,插入到Cookie中。该csrftoken在用户登陆阶段生成,在session结束前保持不变。

  1. 每个响应的POST表单中,都会插入一个隐藏的csrfmiddlewaretoken字段。该字段的值也是对1中的secret进行salt hash,每次请求表单页面都会使用一个随机的salt,因此每次响应中表单里面插入的csrfmiddlewaretoken都是不同的。

  1. 对于每一次HTTP请求,只要request method不是GET, HEAD, OPTIONS or TRACE,都会要求同时在request header的cookie中携带csrftoken,以及在request body中携带csrfmiddlewaretoken,并对两者进行校验。若是缺失或者校验不经过,则返回403 error。

  1. 在校验csrftoken和csrfmiddlewaretoken时,不是直接对比两个token,而是解密后对比两者的秘钥secret是否相同。由于即便用户每次请求在表单中得到的csrfmiddlewaretoken都是变化的,可是在整个session中,secret是保持不变的。

注意,在POST表单中使用csrf token时,要确保表单是提交给本身的web应用的,而不是提交给外部的应用。好比在表单action中指定提交到baidu或者其余网站,别人是没法识别请求中的csrf token的,而且同时也存在泄漏csrf token的风险。

总结

cookie由于其自动在请求中携带的特色,很容易受到CSRF攻击。攻击者不须要获取用户的cookie,也能够直接利用用户的cookie进行恶意操做。CSRF攻击的影响取决于用户所拥有的权限。

因此咱们在web应用设计中要注意,一方面是要严格遵照HTTP规范,GET请求必定是”只读“的,避免接收GET请求进行状态变动(如数据修改等);另外一方面是对于全部设计状态变动的请求,如POST、PUT、DELETE等,都须要进行csrf token校验。

【本文参考】

Introduction to CSRF

Cross Site Request Forgery protection

相关文章
相关标签/搜索