前几天做了一个登录页面的绕过,由于认证返回的token是JWT的格式,于是花了一些时间看了看有关于JWT的东西。
#关于JWT
JWT的全称为Json Web Token。它遵循JOSN格式,与传统的cookie+session的认证方式不同,服务器使用它的好处是只需要保存秘钥信息,通过加密算法验证token即可,减小了保存用户信息的资源开销。 jwt可以分成三部分,header.payload.signature
## header部分
通常它会长成这个样子
{
"alg": "HS256",
"typ": "JWT"
}
其中alg字段指定了token加密的算法,常见的有HMAC算法、RSA算法。
typ声明类型。
## payload部分
通常会长成这样子
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}
会有很多类似的字段,比如用户名,签发时间(iat),过期时间(exp)类似的信息。
## signature部分
这部分主要是用来保证token的完整性。 他的组成也不难,比如这样:signature=HMAC-SHA256(base64UrlEncode(header)+'.'+base64UrlEncode(payload),secret_key)完成的token生成可以使用python的pyjwt库来完成,如果你要修改jwt的一部分内容可以考虑使用https://jwt.io/
# 攻击手法 ## 针对加密方式
首先可以试试,修改alg字段为None即可,类似这样
{
"alg": "None",
"typ": "JWT"
}
那么相应的,你JWT的第三部分也就不需要了,顺便一提,如果对方加入了对None字段的过滤的话,有时替换大小写可以绕过 第二种方法把RSA加密修改为HMAC也不错,因为它是对称加密的,所以在部分情况下好使。 比如:将第一个字段修改成这样
{
"alg": "HS256",
"typ": "jwt"
}
一般情况下都是密钥签名,公钥用来验证。虽然无法获取到密钥,但是公钥往往是有办法获取到。此时便可以把加密方式修改为HS256,然后把共要哦用来签名发给服务器,然后服务器就会那私钥进行解密。
## 爆破秘钥
爆破可以使用github上的工具c-jwt-cracker来完成,但是局限性很大。 首先秘钥不能太复杂,其次还需要一段已知的签过名的token。 基本打比赛偶尔能遇到,实战歇菜。
## 修改kid
kid(key ID)是JWT的header部分的可选参数,作用是用来指定加密算法秘钥。 大概长这个样子
{
"alg": "HS256",
"typ": "jwt",
"kid": "/home/jwt/.ssh/1.pem"
}
由于这部分可以用户输入,在极少数情况下也会有用。 比如说,掌握了某一个老秘钥,但是服务器会定期更新秘钥,如果老秘钥没有删除,就可以在这里指定加密秘钥为老秘钥。
再比如说,如果过滤不严,一些注入之类的骚操作,但是局限性很大。
## 信息泄露
因为jwt简单来说就是base64encode了一段json,所以一些JWT令牌的中间部分会有一些敏感信息。