介绍
- 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
- 安全性
- xss attack Cross-site scripting 跨站脚本攻击 JavaScript可以修改JWT,因为JWT通常放在localStorage或者Cookie中,此时会出现XSS Attack。比如坏人把恶意js代码嵌入到页面中,就可以篡改你的JWT 如何防范?1.签名 2.加密 3.敏感数据不放入JWT中
- CSRF Cross-Site Request Forgery 跨站请求伪造攻击 - 使用cookie攻击 不仅是Session id还是JWT都可能存在Cookie里面,只要存在Cookie中就很容易收到CSRF攻击 如何防范? 无论是JWT还是Session都要有CSRF保护措施
- 重放攻击 Replay Attacks 保证Session id 和JWT过期时间短
- 中间人攻击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 });