JWT?我一直都是这么理解的......
刚才看了learnku的另一篇文章:Laravel项目被入侵了,请问该如何应对和解决呢?,题主怀疑是系统的Token泄露导致的,JWT版本号是"tymon/jwt-auth": "^1.0"
,然后我去本地看了看我的依赖,发现和题主的组件和版本一样。
于是我的担忧来了……所以!无论如何要避免此类事情发生!
JWT组成
众所周知,JWT是由header
、payload
、signature
三者通过.
拼接生成的。
如图所示
- 红色部分代表 header,主要存放JWT的加密方式等核心,由base64加密形成。
- 紫色部分代表 payload,主要存放用户态信息,JWT过期时间等,由base64加密形成。
- 蓝色部分代表 signature,这个是根据
header
+payload
的拼接再加上secret经过某种方式加密形成的(核心)。
JWT生成
本着学习的心态了解一下PHP如何生成JWT,一是重新了解一下JWT,二是想从原理上分析JWT可能存在的问题。
// 现在我有一个已生成的JWT字符串
$token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c';
// 解析$token中第一段取出header
$header = '{"alg": "HS256", "typ": "JWT"}'
// 解析$token中第二段取出payload
$payload = '{"sub": "1234567890","name": "John Doe","iat": 1516239022}'
好了,JWT中前两个已经被base64解析出来了,前两个由于是base64方式加密,相当于明文传输,所以大家不要将敏感信息放到里面去,不然很容易被黑客抓包拦截到,从而获取或修改用户的敏感信息。
那么signature(JWT的核心校验)是怎么生成的呢?带着疑问我去了一趟jwt.io。
发现生成规则后,自己动手丰衣足食……
然后我拿着刚才生成的header
和payload
打开了在线密钥生成,假设我的密钥为:your-256-bit-secret
,按照理论来说应该生成出来的值为:SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
以对应jwt.io上signature
的值。
这里有一个大坑
我生成了个什么东西!!!!
然后经过一番周折发现无论如何生成的都是小写英文加数字的组合……不符合逻辑啊
实在不行了,我去下载了"thans/tp-jwt-auth": "^1.1"
的compser包,看看别人怎么生成的。
不要问我为什么选这个包,我随便找的。。。
翻阅良久,终于找到生成signature
的核心代码:hash_hmac
,从没用过这个函数,然后在官方文档,简单看了一下介绍并分析了一下第四个参数:
true
输出原始二进制数据false
输出小写 16 进制字符串。
然后焕然大悟,知道为什么我在在线密钥生成生成的数据对不上了,网站默认是生成的16进制的字符串。
然后继续向下走,发现生成原始二进制数据也对不上,没关系继续看源码,然后发现问题。
加密之后再次生成,发现还是对不上……
对比之后发现这里有一个小坑:
- 应该生成:
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
- 实际生成:
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV/adQssw5c
经过翻阅源码发现,此base64并非原生base64,话不多说上图,删掉了等号,替换了加号和斜杠,不知道为什么这么做,莫非是是RFC规范这么做的?。
好了,这下就完全没问题了,拿到jwt.io校验一下,嗯通过了,不错。
总结
一直都在用JWT做接口授权,只是对JWT原理略有耳闻,还没有这么深度的分析过,经过这次对JWT的了解,发现最敏感的地方就在SECRET
。如果SECRET
没有泄露的话理应来说不会造成Token的安全风险,逆向的话更是无稽之谈。所以至于题主Token泄露是什么原因,排除服务器挂马、用户设备中毒、商业恶性竞争的话,我也没分析出来。不过大家在产品上线后一定要重新生成SECRET
,防止SECRET
泄露。今天也算没白活,又Get到一个知识点。
本作品采用《CC 协议》,转载必须注明作者和本文链接
:+1:
强!学习了!
跟着学习了 :+1:
感谢 楼主为大家 分析 很详细 很到位
JWT 要求的是Base64Url不是Base64。这篇文章解释了两者的区别。blog.csdn.net/lotus_2015/article/d...
:+1:
强👍,属实奥里给
这个必须要加密才可以 使用得,前端加密,后端解密才可以啊! 直接放上去,就是找死啊!