目录
Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准.该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(单点登录SSO:在多个应用系统中,只需要登录一次,就可以访问其他相互信任的应用系统。)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。
一、JTW的结构
JWT分别由标头(Header)、有效载荷(Payload)和签名(Signature)三个部分组成,采用base64url编码进行加密,以.作为连接的字符串形式。
//base64url编码加密是先做base64加密,然后再将 +
改成 -
、 / 改成 _ ,同时也去除末尾额外添加的 =
字符
例如:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
可以在官网上进行解密查看内容:JSON Web Tokens - jwt.io
Header
header部分承载两部分信息:
一个是typ,表示令牌类型
一个是alg,表示签名所使用的算法,默认是 HMAC SHA256
{
"alg": "HS256",
"typ": "JWT"
}
Payload
payload部分是JWT的主体部分,用于存放有效数据。JWT有七个默认字段可以选择:
iss:发行人
exp:到期时间
sub:主题
aud:用户
nbf:在此之前不可用
iat:发布时间
jti:JWT ID用于标识该JWT
payload示例:
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}
Signature
Signature部分是将前面用base64加密后的header和用base64加密后的payload通过.
拼接起来,然后再用header声明所使用的算法(HS256)进行进行加盐secret加密,然后再对所得到的密文进行base64url加密,最终才得出JWT的第三部分。
HMACSHA256(
base64UrlEncode(header) + "." +base64UrlEncode(payload),
your-256-bit-secret
)
二、JTW、cooker、token之间的区别
参考文章:JWT和cookie/session的区别及优缺点 - Gavin_j - 博客园
三、JWT攻击方式
(1)空加密算法
#前提:服务端允许使用"alg" : "None"(几乎不可能,一般只存在靶场中)
#方法:将header部分的alg改为None,删除掉Signature部分
#脚本:
import jwt
import base64
def b64urlencode(data):
return base64.b64encode(data).replace(b'+', b'-').replace(b'/', b'_').replace(b'=', b'')
print(b64urlencode(b'{"alg":"None"}')+b'.'+b64urlencode(b'{"iat":1669649048,"admin":"true","user":"Tom"}')+b'.')
#生成后的JWT
eyJhbGciOiJOb25lIn0.eyJzdWIiOiAiMTIzNDU2Nzg5MCIsIm5hbWUiOiAiSm9obiBEb2UiLCJpYXQiOiAxNTE2MjM5MDIyfQ.
(2)爆破秘钥
#工具:GitHub - brendan-rius/c-jwt-cracker: JWT brute force cracker written in C
设置第一个JWT的密钥为bcxc,第二个JWT的密钥为jwt
爆破结果:
当签名用的密钥不复杂时,就很容易爆破出来
(3)修改kid
kid是JWT的Header中的一个参数,用于认证token的密钥
{
"alg": "HS256",
"typ": "JWT",
"kid": "ed2Nf8sb-sD6ng0-scs5390g-fFD8sfxG"
}
当用户可以操控它的时候,容易引发以下安全问题:
目录遍历
{
"alg": "HS256",
"typ": "JWT",
"kid": "../../etc/passwd"
}
sql注入
{
"alg": "HS256",
"typ": "JWT",
"kid": "111' || union select database() --"
}
命令执行
{
"alg": "HS256",
"typ": "JWT",
"kid": "ed2Nf8sb-sD6ng0-scs5390g-fFD8sfxG" | whoami;
}
四、webgoat靶场之JWT tokens通关攻略
#webgoat靶场安装参考文章
第四关
本关卡需要我们获得管理员权限并且重置投票,当我们想重置Reset时,会告诉我们:Only an admin user can reset the votes
通过burp抓包获取token
将header部分的alg改为None,将payload部分的admin改为true,并删除掉Signature部分
用burp修改Cookie,修改为新token
成功通关
第五关
本关卡需要我们爆破出密钥,然后再把payload部分的username部分改为admin
#注意点:本关卡还设置了有效时间,就是payload部分的exp,在最后提交的时候需要修改成当前时间
可以利用github上的jwtcrack 进行字典爆破,不过字典要自己去找
爆破结果:
将指定截止时间的exp修改成接下来的几分钟后 (利用网上工具),将username修改为关卡要求的WebGoat,输入密钥爆破结果shipping
将修改后得到JWT提交上去,成功过关
第七关
本关卡需要修改日志文件中2016年已经过期的token来让tom成功结账
修改一下token包里面的iat和exp(iat:发布时间、exp:到期时间)
再利用空加密算法脚本生成新的token
在burp中将Accept-Encoding的值改成新的token
成功通关
第八关
本关卡可以用空加密算法来删除Tom用户,也可以用kid注入,因为空加密上面已经提起过好多次了,所以这次用kid注入来做
#有时间再更