jwt伪造
什么是jwt?
JWT(json web token),它并不是一个具体的技术实现,而更像是一种标准。
JWT规定了数据传输的结构,一串完整的JWT由三段落组成,每个段落用英文句号连接(.)连接,他们分别是:Header、Payload、Signature,所以,常规的JWT内容格式是这样的:AAA.BBB.CCC
并且,这一串内容会base64加密;也就是说base64解码就可以看到实际传输的内容。
常见的jwt加密算法
HS256(HMAC with SHA-256):使用单个密钥进行加密和解密。
HS384(HMAC with SHA-384):与 HS256 类似,但使用更安全的 SHA-384 哈希算法。
HS512(HMAC with SHA-512):与 HS256 类似,但使用更安全的 SHA-512 哈希算法。
RS256(RSA Signature with SHA-256):使用公钥和私钥进行加密和解密。
RS384(RSA Signature with SHA-384):与 RS256 类似,但使用更安全的 SHA-384 哈希算法。
RS512(RSA Signature with SHA-512):与 RS256 类似,但使用更安全的 SHA-512 哈希算法。
ES256(Elliptic Curve Digital Signature Algorithm with SHA-256):使用椭圆曲线密钥对加密和解密。ES384(Elliptic Curve Digital Signature Algorithm with SHA-384):与 ES256 类似,但使用 更安全的 SHA-384 哈希算法。
ES512(Elliptic Curve Digital Signature Algorithm with SHA-512):与 ES256 类似,但使用更安全的 SHA-512 哈希算法。
比较RS256和ES256两种算法,在安全性方面,两种算法都是非常安全的。两种算法的差别在于它们使用的密钥长度不同:
● RS256使用的是RSA算法,因此它使用的是长度较长的密钥。
● ES256使用的是ECDSA算法,因此它使用的是较短的密钥。
因此,如果对性能要求比较高,可以使用ES256,如果对安全性要求比较高,可以使用RS256。
总的来说,选择哪种算法取决于应用的需求和性能要求。两种算法都可以在适当的情况下使用,以满足应用的安全和性能要求。
传统token与jwt方式的区别:
传统token方式:
用户登录成功后,服务端生成一个随机token给用户,并且在服务端(数据库或缓存)中保存一份token,以后用户再来访问时需携带token,服务端接收到token之后,去数据库或缓存中进行校验token的是否超时 、是否合法。
jwt方式:
用户登录成功后,服务端通过jwt生成一个随机token给用户(服务端无需保留token),以后用户再来访问时需携带token,服务端接收到token之后,通过jwt对token进行校验是否超时、是否合法
无验证的jwt
通过请求得到的jwt是eyJhbGciOiJOb25lIiwidHlwIjoiand0In0.W3siaXNzIjoiYWRtaW4iLCJpYXQiOjE2NzYyOTQwNzQsImV4cCI6MTY3NjMwMTI3NCwibmJmIjoxNjc2Mjk0MDc0LCJzdWIiOiJ1c2VyIiwianRpIjoiMThiNDc4YjBlNGE2OTQ0NDc2YTEzNThiOGFhYzJiOGUifV0
通过https://jwt.io/解码发现加密方式是None,这样是不安全的,攻击者可以构造任意用户身份
使用该脚本需要安装相关依赖,参考:pip uninstall jwt pip uninstall PyJWT pip install PyJWT
exp:
import jwt |
xxxxxxxxxx #include<stdio.h>int main(void){ char name[20]; printf(“Enter your name: “); scanf(“%s”,&name); canshu(name); return 0;}void canshu(char name) { printf(“hello my name is %s”,name);}/传入字符串需要使用字符串指针char/c
得到的jwt是
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTY3NjI5NDQ0NCwiZXhwIjoxNjc2MzAxNjQ0LCJuYmYiOjE2NzYyOTQ0NDQsInN1YiI6InVzZXIiLCJqdGkiOiI0YjJhNjAyMTdiM2VlMjYxZWRmNGYxYzhmYjMwYWMxNyJ9.5AFBAQuVTRKMori672FetNVJgyuNZ5zs6ZQSExtyPIM
通过https://jwt.io/发现是HS256加密,但其实后端没有进行严格的验证,我们将加密方式设置为None即可伪造用户身份,参考上面的exp
弱口令
当我们得知一个jwt的加密口令时,如:123456。可以构造对应用户的jwt
import jwt |
暴力破解
c-jwt-cracker
(应该是采用逐位穷举爆破的方法,所以时间很长,只适用于跑短的秘钥)
git clone https://gitclone.com/github.com/brendan-rius/c-jwt-cracker.git
./jwtcracker eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTY3NjI2MzIxMiwiZXhwIjoxNjc2MjcwNDEyLCJuYmYiOjE2NzYyNjMyMTIsInN1YiI6InVzZXIiLCJqdGkiOiI3NmQ3OGRlNjVhZTIxZDBkMzI2ZWNjZWQ3MTA2NDNkZiJ9.3M4CqbJeNhSwJOTtp2DrtbcblZxOqBky8rTsT4HX6S0
hashcat
(采用字典爆破,字典参考https://github.com/wallarm/jwt-secrets/blob/master/jwt.secrets.list 这里使用AMD的CPU貌似需要安装驱动,使用英特尔的可以直接跑出来,kali内存分配的太少了也跑不出来)
hashcat -a 0 -m 16500 eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhZG1pbiIsImlhdCI6MTY2NzY1Njk0MiwiZXhwIjoxNjY3NjY0MTQyLCJuYmYiOjE2Njc2NTY5NDIsInN1YiI6InVzZXIiLCJqdGkiOiJkODMwMGU0MWJkZWI5Y2M1MjIzNzgxMDdkMDE2MzlhOCJ9.lYnVCfleYbtGCZMTtBlRHPn2b9AKLLa2qSe7ksQb53o jwt.secrets.list |
跑出来了直接使用上面的脚本生成jwt即可
亦可以使用脚本生成字典并爆破
生成六位数字典
python .\pydictor.py -base d --len 1 6 -o nums.txt |
exp
# -*- coding: utf-8 -*- |
私钥泄露
当我们获取到私钥以后(dirsearch扫出来private.key),可以构造任意用户的jwt。
import jwt |
秘钥混淆攻击
前提:获取到public.key,并且后端支持HS256和RS256两种算法
分配给我们的jwt是使用rs256进行加密的,验证的jwt是直接使用public验证,那么我们可以直接使用只需要一个钥匙的hs256算法,当我们得到了public.key,直接使用hs256生成jwt即可
import jwt |
后端代码
var express = require('express'); |