JSON Web Token原理深入理解

什么是JWT

JWT全称Json Web Token,翻译为JSON格式的网络令牌,很多时候又简称为Token(JWT是Token的一种实现方式)。它要解决的问题,就是为多种终端设备,提供统一的、安全的令牌格式。因此,JWT只是一个令牌格式而已,你可以把它存储到Cookie,也可以存储到localstorage,没有任何限制!同样的,对于传输,你可以使用任何传输方式来传输JWT,一般来说,我们会使用HTTP请求头(Authorization)来传输它。比如,当登录成功后,服务器可以给客户端响应一个JWT。

JWT的结构解析

img

第一部分我们称它为头部(header),第二部分我们称其为载荷(payload),第三部分是签证(signature)

Header

Header通常由两部分组成:令牌的类型(即JWT)和所使用的签名算法(例如HMAC SHA256或RSA)。 例如:

{
    "alg": "HS256",
    "typ": "JWT"
}

到目前为止,jwt的签名算法有三种:

  • HMAC【哈希消息验证码(对称)】:(HS256/HS384/HS512)

  • RSASSA【RSA签名算法(非对称)】(RS256/RS384/RS512)(一般用这个)

  • ECDSA【椭圆曲线数据签名算法(非对称)】(ES256/ES384/ES512)

Header会被Base64Url编码为JWT的第一部分。即为:

$ echo  -n '{"alg":"HS256","typ":"JWT"}'| base64
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

Base64编码概述:Base64不是一种加密算法,它实际上是一种“二进制转换到文本”的编码方式,它能够将任意二进制数据转换为ASCII字符串的形式,以便在只支持文本的环境中也能够顺利地传输二进制数据。

(1)base64编码:把二进制数据转为字符;

(2)base64解码:把字符转为二进制数据;

Base64编码原理详见:C语言base64实现-优快云博客

payload

载荷就是存放有效信息的地方,它包含声明(要求)。声明有三种类型:

  • registered claims:标准中注册的声明。这里有一组预定义的声明,它们不是强制的,但是推荐

    • iss: jwt签发者
    • sub: jwt所面向的用户
    • aud: 接收jwt的一方
    • exp: jwt的过期时间,这个过期时间必须要大于签发时间
    • nbf: 定义在什么时间之前,该jwt都是不可用的
    • iat: jwt的签发时间
    • jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击
  • public claims:公共的声明

    公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信息,因为该部分在客户端可解密.

  • private claims:私有的声明

    私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息。


问:jwt 上的私有(private)声明和公共(public)声明有什么性质上的区别?

公开声明需要是抗冲突的自定义声明名称。它们的名称应该是 UUID 或以 URL 为前缀,以便为它们创建安全的命名空间并避免冲突。而私有声明不需要抗冲突的自定义声明名称。总结他们的本质区别就是:公共声明必须具有普遍的抗碰撞性,而私有声明则不需要。


Payload会被Base64Url编码为JWT的第二部分。即为:

$ echo -n '{"iat":1593955943,"exp":1593955973,"uid":10,"username":"test","scopes":["admin","user"]}'| base64
eyJ1c2VybmFtZSI6InRlc3QiLCJpYXQiOjE1OTM5NTU5NDMsInVpZCI6MTAsImV4cCI6MTU5Mzk1NTk3Mywic2NvcGVzIjpbImFkbWluIiwidXNlciJdfQ

注意:对于已签名的令牌,此信息尽管可以防止篡改,但任何人都可以读取。除非将其加密,否则请勿将机密信息放入JWT的payload或Header中。

Signature

令牌签名:按照头部固定的签名算法对整个令牌进行签名,该签名的作用是:保证令牌不被伪造和篡改

签名的过程就是对前两部分(头部和负载)通过Base64URL编码后的内容使用服务端存储的私钥头部的加密算法进行加密,生成签名部分的数据,头部、负载、签名三部分通过.符号进行连接。

JWT认证过程

在这里插入图片描述

JWT和普通Token的区别

  • 普通Token在服务端验证的时候,服务端要进行数据的查询操作
  • 使用JWT验证Token的方式是使用服务端存储的私钥进行验证,不需要数据库的查询

前端如何发送token给后端

使用Authorization请求头的方式发送,具体格式如下:

str="Bearer "+token;
'Authorization':str,

Bearer token是一种比较安全的身份验证方式

Basic token和Bearer token的区别

  • Basic token是一种基本的身份验证方式,它使用base64编码的用户名和密码,将其加密成一个字符串,在http request的header中以"Authorization: Basic [编码后的字符串]"的形式发送到服务器进行身份验证。这种身份验证方式的缺点在于,由于用户名和密码是以base64编码的形式传递,因此容易被拦截并进行破解,存在风险。

  • Bearer token是一种更为安全的身份验证方式,它通过在用户登陆成功后,由服务器返回一个随机的token,这个token是具有时效性和唯一性(同一用户,不同时间返回的token不一样)的,客户端在每次请求时,将token放在http request的header中以"Authorization: Bearer [token]"的形式发送到服务器进行身份验证。服务器端通过token来验证客户端的身份是否合法。Bearer token的安全性更高,每个用户拥有独立的token,token的时效性保证了一段时间后即使被截获,也不能被长时间滥用,提高了安全性。

因此,二者之间的本质区别在于安全性的差异。


问:token可以跨域,但是普通session不能跨域的本质原因是什么?
  1. Session是一种服务器端的状态管理机制,而token是一种客户端的认证与授权机制。

  2. Session在服务器端存储,客户端请求时需要将session ID发送到服务器来恢复用户状态,因此只适用于同一域名下的请求。如果在跨域请求时希望保持用户状态,需要跨域共享session ID,但这需要使用特殊的技术手段来实现。

  3. Token则是将认证信息和密钥加密后放在客户端,客户端每次请求时携带该token,在服务器端对该token进行验证并恢复用户身份信息。由于token存储在客户端中,可以跨域使用,但需要注意安全性问题。

因此,Session不能跨域的本质原因是Session需要在服务器端存储和管理,仅适用于同一域名下的请求;而Token是一种可跨域使用的认证授权机制,但需要注意其安全性问题。


问:在使用JWT进行跨域时,需要注意哪些安全问题?
  • CSRF(Cross-site request forgery)攻击:攻击者可以伪造请求,在用户不知情的情况下执行非法操作。为了防止CSRF攻击,可以在JWT中添加CSRF令牌,每次请求时校验CSRF令牌是否匹配。

  • XSS(Cross-site scripting)攻击:攻击者可以通过注入恶意代码来盗取用户的登录信息。为了防止XSS攻击,可以在JWT中添加HttpOnly属性,禁止JavaScript代码读取该cookie。

  • 安全算法的选择:选择安全的签名算法和加密方式来保护JWT的完整性和保密性。通常建议使用HS256算法(使用HMAC SHA-256哈希算法)或RS256算法(使用RSA加密算法)。

  • JWT的有效期和过期处理:设置JWT的有效期和过期处理方式,例如在JWT中添加过期时间和刷新Token等机制,以减少因长时间保留JWT而带来的安全风险。

  • Token管理:管理JWT的签名秘钥和密钥,及时更新并存储安全的密钥,控制Token的发布和撤回,防止Token被盗用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值