当前位置:网站首页>Cookies在XSS和CSRF防御中的作用

Cookies在XSS和CSRF防御中的作用

2022-06-09 10:47:00 Johnny丶me

Cookies 特性

  • 前端数据存储
  • 后端通过http头设置
  • 请求时通过http头传给后端
  • 前端可读写
  • 遵守同源(协议/域名/端口)策略

Cookies 示例

  • 服务端写cookie
    ctx.cookies.set('userId', 1, {
          
        httpOnly: false,
        sameSite: 'strict'
    })
    
  • 客户端读取cookies
    // 取cookie, 获取全部的cookie
    document.cookie
    
  • 客户端设置cookie
    // 直接用 = 即可添加一个新的cookie不会覆盖原来的cookie
    document.cookie="name=joh";
    // 下面是错误的示范,只能在cookies中追加上第一个值,也就是name=joh,后面的不会添加
    document.cookie="name=joh;age=10";
    
  • 客户端删除cookie,是将其有效期设为过去的时间或设为当前时间即可
    document.cookie='name=joh; expires=' + (new Date()).toGMTString()
    

Cookies 特性

  • 域名: cookie可以发挥作用的地方(网址)
  • 有效期: cookie在多长时间内有效
  • 路径: cookie可以作用在url的哪一级,设置了路径只有该路径下才可以使用该cookie
  • http-only: 只能被http协议使用(请求和接收),js不能使用
  • secure: 是否在在https协议中使用,如果是,则在http协议下无法使用

Cookies 作用

  • 存储个性化设置
  • 存储未登录时用户唯一标识
  • 存储已登录用户的凭证
    • 前端提交用户名和密码
    • 后端验证用户名和密码
    • 后端通过http头设置用户凭证
    • 后续访问时后端先验证用户凭证
  • 存储其他业务数据

关于用户凭证的处理

1 ) 通过cookie存储用户签名

  • 用户ID(不安全)

  • 用户ID+签名(推荐)

  • nodejs中处理用户凭证

    var crypt = {
          };
    const KEY  = '&SWLSWkssf**)?!swe^%$'; // 越复杂越好
    
    // 提供加密方法
    crypt.cryptUserId = function(userId) {
          
        var crypto = require('crypto'); // 加密模块
        var sign = crypto.createHmac('sha256', KEY);
        sign.update(userId + ''); // update进行签名,参数是字符串
        return sign.digest('hex'); // 获取16进制签名
    }
    
    module.exports = crypt;
    
  • nodejs响应中设置加密后cookies信息

    const crypt = require('/path/to/crypt')
    
    // 后端提供两个cookies 一个签名后的userID即sign, 一个是纯userID
    // 每次请求通过提供的userID根据同样的算法计算出相关的值和sign进行比较验证身份,下面会有处理
    ctx.cookies.set('sign', crypt.cryptUserId(userId), {
          
        httpOnly: false,
        sameSite: 'strict'
    })
    ctx.cookies.set('userId', userId, {
          
        httpOnly: false,
        sameSite: 'strict'
    })
    
  • nodejs请求中验证用户凭证

    const crypt = require('/path/to/crypt')
    
    var userId = ctx.cookies.get('userId')
    var sign = ctx.cookies.get('sign')
    var computedSign = crypt.cryptUserId(userId)
    // 对比两个签名是否正确
    if(computedSign != sign) {
          
        throw new Error('签名被篡改')
    }
    

2 ) 通过SessionId处理

  • 封装session方法
// session的原理就是把用户数据放在内存中
// 通过给前端数据发送随机字符串(标识),前端不存储任何数据
// 当前端再次请求的时候只需要带上这个标识在内存中找出数据即可标识该用户
// 进一步可以将session数据持久化存储到redis等数据库中,一般不会存储到内存中(容量有限)
// 此处只是session实现的原理
var session = {
    };
var cache = {
    };
session.set = function(userId, obj) {
    
    var sessionId = Math.random();
    if(!cache[sessionId]) {
    
        cache[sessionId].content = obj;
    }
    cache[sessionId].content = obj;
    return sessionId;
}

session.get = function(sessionId) {
    
    return cache[sessionId] && cache[sessionId].content;
}

module.exports = session;
  • 使用session, 设置cookies
const session = require('/path/to/session')

session.set(user.id, {
    
    userId: user.id
})

ctx.cookies.set('sessionId', sessionId, {
    
    httpOnly: true,
    sameSite: 'strict'
})
  • 使用session, 读取cookies
const session = require('/path/to/session')
var sessionId = ctx.cookies.get('sessionId')
var sessionObj = session.get(sessionId)
if(!sessionObj || !sessionObj.userId) {
    
    throw new Error('session不存在')
}
var userId = sessionObj.userId

Cookies和XSS CSRF的关系

  • XSS可能会偷取cookie信息,进而拿到用户的登录态进行模拟登录,并可修改cookie
    • 设置了http-only的cookie不会被js盗取,防止用户账户被盗取
    • 但是XSS除了cookie还可做其他坏事
  • CSRF利用了用户的cookie,盗用信息,但无法读写cookie,最好阻止第三方使用cookie(即sameSite)

Cookies的安全策略

  • 加签名防止篡改
    • 即userID + sign 虽然有公开,但有验证保护
  • 私有变换(加密)
    • 把信息隐藏起来,直接是密文的请求和响应
    • 内部解密读写
      var crypto = require('crypto')
      var KEY = 'SASDKLJFL245*^%$&*SSLlli12'
      
      // 进行加密
      var cipher = crypto.createCipher('des', KEY)
      var text = cipher.update('要加密的字符', 'utf8', 'hex')
      text += cipher.final('hex')
      // 输出
      console.log(text)
      // 解密
      var decipher = crypto.createDecipher('des', KEY)
      var originalText = decipher.update(text, 'hex', 'utf8')
      originalText += decipher.final('utf8')
      console.log(originalText)
      
  • http-only (防止XSS)
    • 只有http请求读写cookie,js无法读取cookie
  • secure
    • 在https协议下有效
    • 防止传输窃听
  • same-site
    • 防止CSRF攻击

相关案例

  • 某校务网站用username作为唯一用户标识,很不安全
  • 某BBS程序使用用户ID作为唯一标识,伪造用户登录
原网站

版权声明
本文为[Johnny丶me]所创,转载请带上原文链接,感谢
https://blog.csdn.net/Tyro_java/article/details/125193778