JWT是什么
JWT(JSON Web Token):用来在用户和服务器之间传递安全可靠的信息
三部分组成:
- eader(头部), 声明类型,这里是JWT,声明加密的算法,最后通过Base64编码
- Payload(数据), 应用层自己带的数据信息。因为该部分是明文的, 所以不可以带敏感信息。 比如可以带 user_id, 但是不可以带 user 的密码等。
- Signature(签名)HMACSHA256(base64Url(header)+.+base64Url(payload),secretKey)
一旦前面两部分数据被篡改,只要服务器加密用的密钥没有泄露,得到的签名肯定和之前的签名不一致,保证了唯一性
如何实现JWT
Token的使用分成了两部分:
-
生成token:登录成功的时候,颁发token
借助第三方库jsonwebtoken,通过jsonwebtoken 的 sign 方法生成一个 token:
第一个参数指的是 Payload
第二个是秘钥,服务端特有
第三个参数是 option,可以定义 token 过期时间 -
验证token:访问某些资源或者接口时,验证token
使用 koa-jwt 中间件进行验证,方式比较简单
app.use(koajwt({
secret: 'test_token'
}).unless({ // 配置白名单
path: [/\/api\/register/, /\/api\/login/]
}))
在分布式系统中,每个子系统都要获取到秘钥,那么这个子系统根据该秘钥可以发布和验证令牌,但有些服务器只需要验证令牌
这时候可以采用非对称加密,利用私钥发布令牌,公钥验证令牌,加密算法可以选择RS256
优缺点
优点:
- json具有通用性,所以可以跨语言
- 组成简单,字节占用小,便于传输
- 服务端无需保存会话信息,很容易进行水平扩展
- 一处生成,多处使用,可以在分布式系统中,解决单点登录问题
- 可防护CSRF攻击(Cookie + Session 的鉴权方式中,鉴权数据(cookie 中的 session_id)是由浏览器自动携带发送到服务端的,借助这个特性,攻击者就可以通过让用户误点攻击链接,达到攻击效果。而 token 是通过客户端本身逻辑作为动态参数加到请求中的,token 也不会轻易泄露出去,因此 token 在 CSRF 防御方面存在天然优势。)
缺点:
- payload部分仅仅是进行简单编码,所以只能用于存储逻辑必需的非敏感信息
- 需要保护好加密密钥,一旦泄露后果不堪设想
- 为避免token被劫持,最好使用https协议
token存放位置
- 存储在localStorage中,每次调用接口的时候都把它当成一个字段传给后台
优点:可以跨域
缺点:Web存储(localStorage/sessionStorage)可以通过同一域Javascript访问。这意味着任何在你的网站上的运行的JavaScript都可以访问Web存储,所以容易受到XSS攻击。 - 存储在cookie中,让它自动发送
优点:可以制定httponly,来防止被JavaScript读取,也可以制定secure,来保证token只在HTTPS下传输。
缺点:不能跨域,而且不符合Restful最佳实践,易受CSRF攻击(简单来说攻击者盗用已经认证过的用户信息,以用户的名义进行一些操作(发邮件、转账等)CSRF不能拿到用户信息,他只是盗用用户的凭证去进行操作) - 拿到之后存储在localStorage中,每次调用接口的时候放在HTTP请求头的Authorization字段里面。
- 加到 url,不安全,容易被截取
主动让token失效
可以在token里面加个随机码,把随机码放到数据库里面。登陆成功就在数据库记录一下随机码,退出登陆和过期就把这条记录删掉。如果随机码存在就能成功登陆,否则就失败,后端返回前端⼀个401的状态码,在axios的响应 拦截器⾥,去获取这个状态,如果发现是401就清理⼀下过去的token,然后重新跳转到登录⻚,获取有效token。
token为什么能够解决CSRF?
CSRF:
cookie和session发送请求时会自动携带,Token不会每次发请求都要携带
但是token也不是一定可以杜绝crfs的,直接拦截请求可以获取token,此时可以使用https,就算获取到了也无法使用