前端安全之csrf攻击

127 阅读2分钟

跨站请求伪造 CSRF(Cross-Site Request Forgery)

危害

盗用用户身份。以用户的名义进行各种操作。如:修改密码(账号盗取)、消费

原理

  1. 用户在浏览器中登录信任的站点 A(如:淘宝网)
  2. 站点 A 验证用户登录信息,成功后在浏览器 Cookie 中写入敏感信息
  3. 用户没有退出站点 A 的情况下,访问了危险网站 B
  4. 危险网站 B 在页面内发起访问站点 A 的请求(用户不知道的情况下),此时浏览器会携带站点 A 的 Cookie
  5. 网站 A 并不能知晓请求是来自危险网站 B

示例

  1. GET 方式
<img src="http://www.taobao.com/member?money=1000" />

csrf-get

csrf-get-test

可以看到,的确是携带了 cookie。应当避免敏感接口使用 get 方式请求

  1. POST 方式

    csrf-post-1

    csrf-post-2.png

    csrf-post-test-1.png

    csrf-post-test-2.png 可以看到,也是携带了 cookie

如何防御?

  1. 敏感操作,必须使用 POST 请求。并不能真正防止 CSRF 攻击,但是能够提升 CSRF 攻击的成本。

  2. 使用验证码。每次敏感操作进行验证码校验,用户体验较差。

  3. 每次请求返回时,服务端在 setcookie 中返回一串伪随机数,并要求用户每次请求时参数中携带该随机数。原则上攻击方不能够获取到被攻击网站的 cookie,所以能够防御。但是存在特殊情况,如 XSS 攻击,导致用户 cookie 泄露

  4. One-Time Tokens(每次不同的伪随机数)

    a. get_token() 令牌生成函数

    function getToken() {
      $token = md5(uniqid(mt_rand(), true));
      return $token;
    }
    

    b. 将令牌放入 session

    $_SESSION[TOKEN_NAME] = getToken();
    

    c. 在 Web 表单中使用隐藏域保存 token

    echo '<input type="hidden" name="' . TOKEN_NAME .'" value="'. $_SESSION[TOKEN_NAME] .'" />';
    

    d. 服务端验证 token 令牌。需要注意的是,用户如果使用浏览器标签页打开两个一样的表单,则前一个表单的 token 会失效,考虑兼容的问题。