浅谈JWT安全问题
写在前头,总结向笔记类文章,内容有些不是我自己的,详情见参考资料
0x00 什么是JWT
JWT全称为: json web token
JWT通常用于实现前端和后端的解耦,同时,它还可以与Restful API一起使用,用于构建身份验证机制
0x01 JWT的格式
JWT的数据分为三部分:头部,有效载荷,签名(图来自freebuf一篇文章,具体找不到了)
通过base64编码起来
使用点号进行划分,比如一个JWT如:
eyJraWQiOiJrZXlzLzNjM2MyZWExYzNmMTEzZjY0OWRjOTM4OWRkNzFiODUxIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJkdWJoZTEyMyJ9.XicP4pq_WIF2bAVtPmAlWIvAUad_eeBhDOQe2MXwHrE8a7930LlfQq1lFqBs0wLMhht6Z9BQXBRos9jvQ7eumEUFWFYKRZfu9POTOEE79wxNwTxGdHc5VidvrwiytkRMtGKIyhbv68duFPI68Qnzh0z0M7t5LkEDvNivfOrxdxwb7IQsAuenKzF67Z6UArbZE8odNZAA9IYaWHeh1b4OUG0OPM3saXYSG-Q1R5X_5nlWogHHYwy2kD9v4nk1BaQ5kHJIl8B3Nc77gVIIVvzI9N_klPcX5xsuw9SsUfr9d99kaKyMUSXxeiZVM-7os_dw3ttz2f-TJSNI0DYprHHLFw
1,头部
eyJraWQiOiJrZXlzLzNjM2MyZWExYzNmMTEzZjY0OWRjOTM4OWRkNzFiODUxIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYifQ
解码为:
{“kid”:”keys/3c3c2ea1c3f113f649dc9389dd71b851",”typ”:”JWT”,”alg”:”RS256"}
包括了typ类型,alg:签名算法
2,有效载荷
eyJzdWIiOiJkdWJoZTEyMyJ9
有效载荷用来存储用户的数据,解码之后为
{"sub":"dubhe123"}
3,签名
XicP4pq_WIF2bAVtPmAlWIvAUad_eeBhDOQe2MXwHrE8a7930LlfQq1lFqBs0wLMhht6Z9BQXBRos9jvQ7eumEUFWFYKRZfu9POTOEE79wxNwTxGdHc5VidvrwiytkRMtGKIyhbv68duFPI68Qnzh0z0M7t5LkEDvNivfOrxdxwb7IQsAuenKzF67Z6UArbZE8odNZAA9IYaWHeh1b4OUG0OPM3saXYSG-Q1R5X_5nlWogHHYwy2kD9v4nk1BaQ5kHJIl8B3Nc77gVIIVvzI9N_klPcX5xsuw9SsUfr9d99kaKyMUSXxeiZVM-7os_dw3ttz2f-TJSNI0DYprHHLFw
由于头部和有效载荷以明文形式存储,因此,需要使用签名来防止数据被篡改。
提供数据的相关函数使用的签名算法通常是RS256(RSA非对称加密和私钥签名)和HS256(HMAC SHA256对称加密)算法。
如使用HS256的加密方式为:
HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
0X02 如何攻击JWT
1,敏感信息泄露
因为有效载荷是明文传输的,如果有效载荷存在敏感信息的话就会发生信息泄露
2,将签名算法改为none
使用工具: JWTPyCrack
python jwtcrack.py -m generate -s {\"admin\":\"True\"}
3,未校验签名
直接替换数据,使用https://jwt.io/#debugger
插入一些常见测试payload,如注入,xss等
4,爆破弱key
使用工具:JWTPyCrack ,只支持明文,有些时候可能还要考虑base64encode的情况,base64的情况,要自己编写脚本
python jwtcrack.py -m blasting -s eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.keH6T3x1z7mmhKL1T3r9sQdAxxdzB6siemGMr_6ZOwU --kf 2.txt
除此之外,我们也可以用hashcat来爆破
爆破hahs少不了一个好的字典,而hashcat rules文件夹下其实有不少规则,我们也可以直接拿来用,生成字典:(b0b064.rule来源于Hob0Rules)
hashcat64.exe --stdout password.txt -r rules/hob064.rule -o pasword_new.txt --force
不想生成文件占磁盘,也可以直接用规则来爆破
hashcat64.exe -a 0 -m 16500 jwt_token jwt_key.txt -r rules/d3ad0ne.rule --force
当然也可以用掩码方式,爆破出来的时间取决于key的长度和GPU的性能
0x03 拓展:accessToken与refreshToken问题
风险点:
未校验access token和refresh token是否属于同一个用户,导致A用户可使用自己的refresh token去刷新B用户的access token,垂直越权
建议:
使用jwt令牌的最佳位置是服务器之间的通信。在普通的web应用程序中,最好使用普通的旧cookies。
例子:
webgoat 8 ,使用A账号的refresh token 和 过期B的access_token去刷新 B的access_token
0x04 实战记录
1,开源程序默认key未修改
某众测厂商默认key直接伪造超级管理员进去
github标志,开源系统直接跟过去
有默认值,虽然作者再三提醒,但鉴于人的本质惰性,相信很多管理员都是不会去修改的,直接伪造超级管理员进去
2,accessToken与refreshToken问题
某厂商可用A用户refreshToken刷新B用户的access_token
假如获取到B用户的过期access_token,那么就可以用A的refresh_token去刷新了
B用户的access_token与refresh_token
使用A用户的refresh_token去刷新B用户的access_token
正常B用户的请求
替换之后的请求,成功请求
这里过期的access_token可以在搜索引擎搜到或者评论等信息泄漏
0x05 总结
简单列举了一下自己遇到的jwt两个案例,笔记向文章没啥好说的。
0x06 参考资料