无密钥解码token令牌的header和payload
这为什么
不知道大家在接触JWT的token后有没有想过为什么我用了各种加密方式加密后的token在不告诉在线解密工具密钥的时候他就能解密出来我token里面的信息。而且大多数解密工具在解密时也不需要我们提供密钥。
JWT解释
百度一下你就知道 JWT 时JSON WEB TOKEN ,也就是说是一个json令牌
JWT(JSON Web Token)是一种用于双方之间传递安全信息的简洁的、URL安全的表述性声明规范。它由三个部分组成:头部,载荷和签名。
- 头: 头部包含了令牌的类型和加密算法的信息。
- 体: 载荷是存放有效信息的地方。它可以包含用户的相关信息,例如用户的ID、用户名等。
- 尾: 签名是用来验证令牌的完整性的。它是头部和载荷的结合,通过指定的秘钥进行加密生成的。
上代码
本次使用的token
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyTmFtZSI6ImFkbWluIiwidWlkIjoiMmIyMmJjNjUtZGU5YS00ZGRlLWJjZDctNjMyNWQ0NWViNWQxIiwibG9naW5UaW1lIjoxNjcyNzM5NDk4MjEyLCJleHBpcmVUaW1lIjoxNjcyNzM5Nzk4MjEyfQ.8wrNGKSCrdUg_sz8JyVgsxpHigFJ9pk_gs4rwc5T5v4
在线解析后的结果是
代码复现
从上面图中的代码可以看出,我在不借助密钥的情况下,仅使用base64就已经获得的头和体 这里基本上可以猜测出在线解析JWT的大致逻辑了,但为什么在解析尾的时候报错了。
尾解析报错是为啥
明明三段的编码都是base64,但前两段成功了,最后一段报错。
这是因为在JWT的生成时的规则不是三段都是一样的base64。
JWT在生成token的时候是会先将头和体进行普通的base64然后再用这两个已经编码过的字符串去生成签名。但签名后 (第三段不是token整体) 的字符串也是经过编码的。
至于不一样的base64编码其实是添加了一层url编码
可以冲sign的代码中看出
通过代码截图可以看出,默认传的tue导致是用的encodeUrlSafe,而不是encode所以导致我们解码时部分字符解不出来导致的。
所以当解码签名时应该使用下面代码
public static void main(String[] args) {
String token ="eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyTmFtZSI6ImFkbWluIiwidWlkIjoiMmIyMmJjNjUtZGU5YS00ZGRlLWJjZDctNjMyNWQ0NWViNWQxIiwibG9naW5UaW1lIjoxNjcyNzM5NDk4MjEyLCJleHBpcmVUaW1lIjoxNjcyNzM5Nzk4MjEyfQ.8wrNGKSCrdUg_sz8JyVgsxpHigFJ9pk_gs4rwc5T5v4";
String[] split = token.split("\\.");
System.out.println("头:"+ split[0]);
System.out.println("体:"+ split[1]);
System.out.println("尾:"+ split[2]);
System.out.println("解密 base64");
Decoder decoder = Base64.getDecoder();
System.out.println("头:"+ new String(decoder.decode(split[0])));
System.out.println("体:"+ new String(decoder.decode(split[1])));
System.out.println("尾:"+ new String(Base64.getUrlDecoder().decode(split[2])));
}
但结果是这样的
到这里就知道为什么解码失败了把,那么还会有个问题就是,我的信息在不用密钥的时候都已经暴露了,那怎么确定信息的安全呢?