csrf攻击原理和防御-生成token防御代码

前言

CSRF(Cross-site request forgery,跨站请求伪造,恶意网站伪造身份冒充你向目标服务器发送请求。CSRF能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账......造成的问题包括:个人隐私泄露以及财产安全。

攻击原理

csrf攻击通过利用浏览器机制:发送请求的域相同时,浏览器会自动携带相同cookie.具体原理做法如下:

客户刚登录完目标网站,目标网站下发了信任凭证cookie.客户没有执行登出操作,在目标网站仍然开启的情况下,进入了恶意网站.恶意网站内,攻击行为是向目标网站的服务器发起请求,恶意网站会把请求域名设置的和目标网站cookie的Domain相同.利用同一个浏览器下发送请求时,请求域名和domain相同,会携带该domain属于的cookie这一点,恶意网站请求可以携带上目标网站的cookie.目标网站的服务器接受到请求后,会认为这是用户的操作,就会去执行操作内容

如下请求,是恶意网站的常见代码,img或a向目标服务器发送请求,由于请求域(xiaodidi.com)和目标网站域相同,请求时就会自动携带上xiaodidi.com域的相关cookie

<img src="http://www.xiaodidi.com....>
<a href=
"http://www.xiaodidi.com....>

攻击代码举例

恶意网站只需要发送如下一个请求给银行,银行那边就会给这个id的用户扣款1000

<img src=http://www.mybank.com/Transfer.php?toBankId=11&money=1000>

解决csrf方法

csrf攻击利用了浏览器在请求域相同时,会携带相同cookie,达到攻击目的.从这个角度想,我们防止csrf攻击可以,我们可以额外添加一个token身份验证,因为token不是cookie,恶意网站没有办法拿到token放到请求中.服务端接受请求时去判断cookie和token是否正确,双管齐下.

具体到项目中流程是:

  • 第一次登录的时候,服务端生成token,通过响应头返回
  • 客户端拿到响应头的token,存储在localstorage中(一定不能在cookie中)
  • 客户端设置全局的请求配置,给每个请求头都加上token
  • 服务端拿到前端请求的token,解密token对比验证身份

实现代码:

ps:用nodejs做服务端

1.第一次登录的时候,服务端node用插件jsonwebtoken生成token,在express的res.set方法中将token放入响应头中,返回给客户端

下载jsonwebtoken,生成token,

//生成token
const jwt = require('jsonwebtoken');
let token = jwt.sign(username, privateKey, { algorithm: 'RS256' });

res.set方法中将token放入响应头中

res.set('X-ACCESS-TOKEN', token)
      //添加token, 向header里面添加一个自定义的字段,
      req.session.username = user["username"];
      res.send({
        code: 1,
        username: user["username"],
        message: "用户登录成功"
      })

2.客户端在ajax请求的success回调中拿到响应头的token,存储在localstorage中

const post = (url, data) => {
  return new Promise((resolve, reject) => {
    $.ajax({
      url,
      type: 'POST',
      data,
     //xhr内部包含响应头内容,具体可查看ajax文档
      success: (res, status, xhr) => {
        res.status = status;
        res.xhr = xhr;
        resolve(res)
      },
      error: (err) => {
        reject(err);
      }
    })
  })
}
//rs是resolve()方法中的内容,这里省略了.then
//jquery.ajax内部参数xhr中通过getResponseHeader可以获取header内的具体内容
let token = rs.xhr.getResponseHeader("x-access-token")
localStorage.setItem('token', token);

3.客户端设置全局的请求配置,给每个请求头都加上token

 $.ajaxSetup({
//全局发送请求前配置 beforeSend(xhr, setting) { let token
= localStorage.getItem('token');
       xhr.setRequestHeader(
'x-access-token', token); }, complete(xhr, setting) { if (xhr.responseJSON.code === 401) { alert(xhr.responseJSON.message) router.go('/index') } } })

4.服务端拿到前端请求的token,解密token对比验证身份,不合法的身份返回401

const jwt = require('jsonwebtoken')
function auth(req, res, next) {
  if (req.session.username) {
    try {
      let token = req.get('x-access-token');
      //对称
      let rs = jwt.verify(token, 'lagouadmin')
      if (rs === req.session.username) {
        next();
      } else {
        res.send({
          code: 401,
          message: "非法访问"
        })
      }
    } catch (error) {
      log.error(req.session.username + " 登录失败 " + error.message)
      res.send({
        code: 401,
        message: "非法访问"
      })
    }
  } else {
    res.send({
      code: 401,
      message: "非法访问"
    })
  }
}

module.exports = auth;

以上就是一个csrf防守生成token的代码实现流程

 

posted @ 2019-09-30 20:55  大笛子  阅读(818)  评论(0编辑  收藏  举报