谈谈CSRF

CSRF介绍前端

  • 英文:Cross Site Request Forgy
  • 中文:跨站请求伪造
  • 攻击者在其余的网站对目标网站产生了影响

CSRF攻击危害

  • 利用用户登陆态
  • 用户不知情
  • 完成业务请求
  • 盗取用户资金(转帐,消费)

    就算警察寻找是谁,也只能找到用户,找不到攻击者,由于攻击者用的ip和cookie都是用户的。node

CSRF攻击防护

csrf防护核心思想就是利用攻击者不会访问目标网站的前端,只会去访问目标网站的后端,因此若是在目标网站的前端增长验证信息,那就会有效防护csrf攻击,由于csrf没法获取这个验证信息,也就没法获得后端的正确响应。ajax

第一种方法

禁止第三方网站携带cookie后端

在cookie中加一个same-site属性 可是兼容性不好,只有不多的浏览器兼容。浏览器

第二种方法

在前端页面加入验证信息,好比:cookie

  1. 验证码
    1. 加入token

验证码

这须要先后端协同
1:前端加入验证码输入框。
2:后端为前端提供这个验证码,而且在提交的时候进行验证,还有后端还要记住这个验证码是什么,也就是保存下来,以便有第三方进行csrf攻击时进行判断。
node.js开发后端的话,有ccap这个插件能够用,它能够生成图形验证码。并发

这个能够有效防护csrf,可是每次都要让用户输入验证码进行验证,下降了用户体验。并且前端提交后,后端还要再校验一下验证码对不对。dom


token

token就是一个随机字符串,放在前端的请求内容中,也能够放在cookie中。post

token生成机制:网站

 1 // 后端要作的事情
 2 // 随机生成token
 3 var csrfToken = parseInt(Math.random() * 9999999, 10);
 4  
 5 // 后端生成token而且保存在cookie中
 6 ctx.cookies.set('csrfToken', csrfToken);
 7  
 8  
 9 // 前端要作的事情
10 // 放置一个表单,不会显示出来,设置隐藏
11 <input name="csrfToken" value=csrfToken><input>

 


而后在相应的动做里进行判断: 

 1 function action(req, res){
 2 var data;
 3 if(req.method.toLowerCase() === 'post'){
 4 data = req.body;
 5 }else{
 6 data = req.query;
 7 }
 8 if(!data.crsfToken){
 9 throw new('csrf token is null');
10 }else if(data.csrfToken !== req.cookies.get('csrfToken')){
11 throw new('csrfToken 错误');
12 }
13 }

 


使用token须要注意的地方
 

  • 若是是经过表单提交,则能够直接将token值放在表单里面提交。
  • 若是是ajax请求,则通常是经过将token放在页面的另一个地方,好比放在meta中。
meta{name="csrf_token", content=csrfToken}

 

刷新后,在页面的head中多了一个meta,在ajax请求以前,就能够经过js把这个meta中的toke值取出来,一并发到后台去。

注意:

若是用户打开了不少页面或者不少提交表单,每一个页面和表单都是对应不一样的token,由于cookies里面只能放置一个token,用户提交只能是提交最后一个页面的token或者是最后一个表单的token,因此这个问题也比较特殊,如何处理。须要思考。


CSRF中的referer

referer是http协议中的一个请求头,来自攻击网站。因此还有一个防护方式:验证referer,禁止来自第三方网站的请求。

 1 // 在相应的动做里
 2 function action(req, res){
 3 var data;
 4 if(req.method.toLowerCase() === 'post'){
 5 data = req.body;
 6 }else{
 7 data = req.query;
 8 }
 9 var referer = res.headers.referer;
10 // 经过使用indexOf判断
11 if(referer indexOf('localhost') === '-1'){
12 throw new('请求非法');
13 }
14  
15 // 更好的作法是下面这个,由于referer是http://整个url地址,若是url其余部分有localhost,上面的表达式也能够被匹配到
16 if(!/^http:\/\/localhost/.test(referer)){
17 throw new('请求非法');
18 }
19 }

 


这里面有几个注意的点: 

  • 从本地磁盘访问,没有refere,由于是同域,能够将ftp改为http形式,好比http://127.0.0.1/
  • 经过http访问,有referer。

 参考

http://godkun.me/2018/01/10/CSRF%E7%A0%94%E7%A9%B6/

相关文章
相关标签/搜索