noede.js学习之JWT

1,183 阅读3分钟

介绍

  • json web token是一个开放标准
  • 定义了一种紧凑且独立的方式,可以将各方之间的信息作为json对象进行安全传输
  • 该信息可以验证和信任,因为是经过数字签名的

构成

  • 头部(header)
  • 有效载荷(playoad)
  • 签名(Signature)

例子

Header

  • 本质上是一个json,其中有2个字段
  • typ:token令牌的类型,这里固定为JWT
  • alg:使用的hash算法,例如:HMAC SHA256 或者 RSA

Header编码前后

生成令牌中把json用base64encode变成base64字符串

Signature

  • 对Header和Payload部分进行签名
  • 保证Token在传输的过程中没有被篡改或者损坏
  • 头部+有效载荷+密钥字

Signature算法

JWT vs. Session

  • 可拓展性 1.水平扩展 - 加服务器 2.垂直扩展 - 加服务器硬件性能(磁盘内存CPU等) Session数据通过文件或者Redis存在服务器中,在水平拓展方案中,需要专门创建一个独立专门中心式的session存储系统,以便于所有的服务器都可以访问Session) JWT可以无缝介入水平拓展,因为基于Toking令牌身份验证是无状态的,所以不需要在session中存储用户信息,应用程序可以轻松拓展,因为可以使用token从不同服务器中访问资源,不能担心用户是否真正登陆在某台服务器上,可以节约成本 程序小不需要在多台服务器拓展,就可以使用Session
  • 安全性
  1. xss attack Cross-site scripting 跨站脚本攻击 JavaScript可以修改JWT,因为JWT通常放在localStorage或者Cookie中,此时会出现XSS Attack。比如坏人把恶意js代码嵌入到页面中,就可以篡改你的JWT 如何防范?1.签名 2.加密 3.敏感数据不放入JWT中
  2. CSRF Cross-Site Request Forgery 跨站请求伪造攻击 - 使用cookie攻击 不仅是Session id还是JWT都可能存在Cookie里面,只要存在Cookie中就很容易收到CSRF攻击 如何防范? 无论是JWT还是Session都要有CSRF保护措施
  3. 重放攻击 Replay Attacks 保证Session id 和JWT过期时间短
  4. 中间人攻击Man-in-the-middle attack 使用HTTPS,在传输期间默认加密,可以有效防范中间人攻击
  • RESTful API REST其中一个限制是无状态Stateless - 所有用户会话信息都保存在客户端。 Session是有状态的认证方式不能用作RESTful API
  • 性能 JWT性能:在客户端向服务端发送请求时,可能有大量用户信息在JWT中,每个HTTP请求都会产生大量的开销。 如果Session,只会有少量开销,Session id非常小。但是需要每个请求都要在服务器上查找session,也需要消耗性能。因为JWT是JSON,而且字符串里里面包含了很多完整信息,不需要数据库查询,JWT用空间(数据量大)换时间(不需要查询时间少)
  • 时效性 JWT时效性比Session差,JWT必须等到过期时间才会销毁,Session可以在服务器主动销毁

在 Node.js 中使用 JWT

操作步骤

  • 安装jsonwebtoken

  • 签名(对json对象进行签名,生成token)

const token = jsonwebtoken.sign({ _id, name }, secret, { expiresIn: '1d' });
  • 验证(把token进行验证看用户发来的是否是正确的签名以及验证token是否正确) 以上都在命令行里操作,对于不需要保存成文件的代码,都可以这么操作

  • 登录授权
  async login(ctx) {
    ctx.verifyParams({
      name: { type: 'string', required: true },
      password: { type: 'string', required: true },
    });
    const user = await User.findOne(ctx.request.body);
    if (!user) { ctx.throw(401, '用户名或密码不正确'); }
    const { _id, name } = user;
    const token = jsonwebtoken.sign({ _id, name }, secret, { expiresIn: '1d' });
    ctx.body = { token };
  }
  • 使用 koa-jwt插件
const jwt = require('koa-jwt');
const auth = jwt({ secret });