一、加密算法的分类
1.1 对称加密
- 使用相同的密钥
- 在对称加密中,公钥和私钥的一样的,即使用相同的密钥进行加密解密
- 加密速度快
- 对称加密算法通常比非对称加密算法快,因为使用了相同的密钥
- 安全传输问题
- 因为公钥和私钥是一样的,在网络通信过程中传递密钥,如果被拦截,通信的安全将受到威胁
- 常见的算法
- DES、3DES、TDEA、Blowfish、RC5等
1.2 非对称加密
- 使用一对公钥和私钥进行加密解密
- 公钥和私钥的不一样的
- 一般在客户端使用公钥对账号密码进行加密,然后传递给后端,后端通过私钥进行解密
- 公钥可以分发,安全性有保障
- 使用公钥加密的数据,只能通过对应的私钥才能解密,即在网络通信过程中被拦截,也无法解密获取数据
- 加密速度相对于对称算法来说比较慢
- 常见的算法
- RSA、DSA、Rabin、ECC、D-H等
1.3 摘要算法
摘要算法又称哈希/散列算法,它是通过一个函数,把任意长度的数据转换为一个长度固定的数据串(通常采用16进制的字符串表示),算法不可逆。
虽然算法不可逆,但存在碰撞的可能,即相同的数据加密后产生的数据串是一样的,即网络中采用的暴力破解法来破解摘要算法。
二、Token
token(令牌)是一种用于身份认证和授权的字符串,它在客户端和服务器之间传递,用于标识身份和访问权限,token本身一般会包含用户的一些身份信息、token的有效期等数据,用于校验token的合法性和有效性
- 认证
- 当用户输入账号密码后,后端会生成一个token,并将其发给客户端,用于表明身份
- 授权
- token还可以用于授权,即某些资源的访问的权限,在某些情况下,token可能会包含某些权限/角色的信息
- 无状态
- token认证是无状态的,即服务器不会在自身存储用户的登录状态
- 用户的每个请求都包含token,服务器通过校验token来进行身份验证
三、JWT
3.1 JWT组成
JWT(JSON WEB TOKEN)是一种常见的token格式,它是一种轻量级的、自包含的方式来表示信息。
- JWT通常包含一些标准的声明
- 令牌的颁发者
- 过期时间
- 自定义的声明
- 用户的ID、角色等
- JWT由三部分组成
- 头部(header)
- 令牌头部,记录了整个令牌的类型和签名算法
- 载荷(payload)
- 令牌载荷,记录了保存的用户主体信息,如你要保存的用户信息可以放在这里
- 签名(signature)
- 令牌签名,按照头部固定的签名算法对整个令牌进行签名,该签名的作用是:保证令牌不被伪造和篡改
- 头部(header)
它们组合而成的完整格式:header.payload.signature
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJpYXQiOjE1ODc1NDgyMTV9.BCwUy3jnUQ_E6TqCayc7rCHkx-vxxdagUwPOWqwYCFc
3.2 header
header是令牌头部,记录了整个令牌的类型和签名算法,它的格式为一个json对象
- alg:signature部分使用的签名算法,通常可以取两个值
- HS256:对称算法
- RS256:非对称算法
- typ:整个令牌的类型,固定写JWT即可
{
"alg":"HS256",
"typ":"JWT"
}
设置好header后,就可以生成header部分,具体的生成方式,就是把header部分使用base64 url编码即可
base64 url不是一个加密算法,而是一种编码方式,它是在base64算法的基础上对
+、=、/三个字符做出特殊处理的算法
浏览器提供了btoa函数
const header = window.btoa(JSON.stringify({
"alg":"HS256",
"typ":"JWT"
}))
// 得到:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
同理通过atob函数解码
window.atob(header)
// 得到:{"alg":"HS256","typ":"JWT"}
3.3 payload
这部分是JWT的主体信息,它为json对象
- ss:发行该jwt的是谁,可以写公司名字,也可以写服务名称
- iat:该jwt的发放时间,通常写当前时间的时间戳
- exp:该jwt的到期时间,通常写时间戳
- sub:该jwt是用于干嘛的
- aud:该jwt是发放给哪个终端的,可以是终端类型,也可以是用户名称,随意一点
- nbf:一个时间点,在该时间点到达之前,这个令牌是不可用的
- jti:jwt的唯一编号,设置此项的目的,主要是为了防止重放攻击(重放攻击是在某些场景下,用户使用之前的令牌发送到服务器,被服务器正确的识别,从而导致不可预期的行为发生)
{
"ss":"发行者",
"iat":"发布时间",
"exp":"到期时间",
"sub":"主题",
"aud":"听众",
"nbf":"在此之前不可用",
"jti":"JWT ID"
}
与header一样,payload也是通过base64 url 进行编码转换的
3.4 signature
这一部分是jwt的签名,这部分的生成,是对前面两个部分的编码结果,按照头部指定的方式进行加密
比如:头部指定的加密方法是HS256,前面两部分的编码结果是eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJpYXQiOjE1ODc1NDgyMTV9
则第三部分就是用对称加密算法HS256对字符串eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJpYXQiOjE1ODc1NDgyMTV9进行加密,当然你得指定一个秘钥,比如shhhhh
HS256(`eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJpYXQiOjE1ODc1NDgyMTV9`, "shhhhh")
// 得到:BCwUy3jnUQ_E6TqCayc7rCHkx-vxxdagUwPOWqwYCFc
最终,将三部分组合在一起,就得到了完整的jwt
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIiLCJpYXQiOjE1ODc1NDgyMTV9.BCwUy3jnUQ_E6TqCayc7rCHkx-vxxdagUwPOWqwYCFc
由于签名使用的秘钥保存在服务器,这样一来,客户端就无法伪造出签名,因为它拿不到秘钥。
换句话说,之所以说无法伪造jwt,就是因为第三部分的存在。
而前面两部分并没有加密,只是一个编码结果而已,可以认为几乎是明文传输
这不会造成太大的问题,因为既然用户登陆成功了,它当然有权力查看自己的用户信息
甚至在某些网站,用户的基本信息可以被任何人查看
你要保证的,是不要把敏感的信息存放到jwt中,比如密码
3.5 面试 阐述JWT的令牌格式
token分为三个部分,分别为header、payload、signature 其中header为头部令牌,记录了token的类型和签名算法;payload为主体信息,包含令牌的过期时间、发布时间、发行者、主体内容等;signature为令牌签名,是根据前面两部分进行加密后得到的结果 token有防篡改的特点,如果攻击者改动了前面两个部分,会导致和第三个部分对应不上,使得token失效,而攻击者不知道第三部分的加密密钥,因此又无法修改第三部分的值 所以在密钥不泄露的前提下,一个验证通过的token是值得被信任的