初识JWT攻击
什么是JWT
JSON Web Token(JWT) 是一种标准化格式,用于在系统之间发送加密签名的 JSON 数据。与经典会话令牌不同,服务器所需的所有数据都存储在 JWT 本身的客户端中。
JWT 格式
JWT 由 3 部分组成:头部、有效负载和签名。它们均由点分隔,如以下示例所示:
1 | 1.头部(Header)包含了关于该 JWT 的元数据,如令牌的类型("typ")和签名算法("alg")等。 |
JWT攻击
1 | JWT(JSON Web Token)本身并不越权,但是如果在使用和验证 JWT 的过程中存在安全漏洞或错误的实现,可能导致越权问题。 |
通过Burp Suite靶场学习JWT攻击
一、通过未经验证的签名绕过 JWT 身份验证(JWT authentication bypass via unverified signature)
1 | JWT 库通常提供一种验证令牌的方法和另一种仅对其进行解码的方法。例如,Node.js 库jsonwebtoken有verify()和decode()。 |
1、开启实验环境,使用账号登录抓包
2、将访问目录改为/admin,然后尝试访问,可以看到服务器返回401 Unauthorized,代表身份验证未通过,并且在JWT的Payload部分有用户名信息
3、将用户名wiener改为administrator,,现在我们就可以成功访问到管理员面板
4、然后使用管理员权限删除对应的用户即可
二、通过有缺陷的签名验证绕过 JWT 身份验证(JWT authentication bypass via flawed signature verification)
1 | JWT 标头包含一个alg参数。这告诉服务器使用哪种算法对令牌进行签名,以及在验证签名时需要使用哪种算法。 |
1、开启实验环境,使用账号登录抓包
2、将访问目录改为/admin,然后尝试访问,可以看到服务器返回401 Unauthorized,代表身份验证未通过,并且在JWT的Payload部分有用户名信息
3、将头部中的alg改none,将用户名wiener改为administrator,现在我们就可以成功访问到管理员面板(因为设置了签名验证参数alg为none,所以最后的签名就没有意义的,将签名部分删除,记得不要删掉最后的.)
4、然后使用管理员权限删除对应的用户即可
三、通过弱签名密钥绕过 JWT 身份验证(JWT authentication bypass via weak signing key)
1 | 在实现 JWT 应用程序时,如果开发人员使用了弱密钥,这会导致攻击者可以很容易的猜解出对应的密钥,然后使用密钥通过有效签名对令牌进行重新签名。 |
1、开启实验环境,使用账号登录抓包
2、将访问目录改为/admin,然后尝试访问,可以看到服务器返回401 Unauthorized,代表身份验证未通过
3、使用hashcat爆破密钥
1 | hashcat -a 0 -m 16500 eyJraWQiOiI1M2Y1ZjAxMi03NjI3LTRlNzQtODhlNS0zY2JkY2VmY2E0YWYiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJwb3J0c3dpZ2dlciIsInN1YiI6IndpZW5lciIsImV4cCI6MTcwMDgwNzk3OX0.EOjDT3rM6jGbdWFNHeS5RyVDg9-vfswjfjiiipeBZ4U secret.txt |
可以看到爆破出密钥为secret1
4、利用密钥通过有效签名对令牌进行重新签名
5、成功访问到管理员面板
6、然后使用管理员权限删除对应的用户即可
四、通过 jwk 标头注入绕过 JWT 身份验证(JWT authentication bypass via jwk header injection)
1 | 根据JWS规范,只有alg标头参数是强制的。但实际上,JWT 标头(也称为 JOSE 标头)通常包含其他几个参数。攻击者特别感兴趣的是以下内容。 |
通过 jwk 参数注入自签名 JWT
1 | JSON Web 签名 (JWS) 规范描述了一个可选的jwk标头参数,服务器可以使用该参数以 JWK 格式将其公钥直接嵌入到令牌本身中。 |
1、开启实验环境,使用账号登录抓包
2、将访问目录改为/admin,然后尝试访问,可以看到服务器返回401 Unauthorized,代表身份验证未通过
3、使用jwk注入,使用JWT Editor插件生成新的 RSA 密钥
4、将用户名修改为administrator,然后注入刚才生成的RSA密钥
5、注入完成后,发送请求,可以看到已经可以成功访问管理员面板了
6、然后使用管理员权限删除对应的用户即可
五、通过 jku 标头注入绕过 JWT 身份验证(JWT authentication bypass via jku header injection)
1 | jwk某些服务器允许您使用(JWK Set URL) 参数来引用包含密钥的 JWK Set,而不是直接使用标头参数嵌入jku公钥。当验证签名时,服务器从该 URL 中获取相关密钥。 |
1、开启实验环境,使用账号登录抓包
2、将访问目录改为/admin,然后尝试访问,可以看到服务器返回401 Unauthorized,代表身份验证未通过
3、通过jku注入,使用JWT Editor插件生成新的 RSA 密钥
4、进入服务器,将Body改为
1 | { |
5、将生成的RSA密钥内容复制到Body中
1 | { |
6、将JWT的头部修改为如下(当验证签名时,服务器从会直接从jku指定的URL中获取相关密钥)
1 | { |
7、然后选择刚才生成的RSA密钥对JWT进行重新签名
8、重新签名之后,发送请求,就可以成功访问管理员面板了
9、然后使用管理员权限删除指定账户即可
六、通过 Kid 标头路径遍历绕过 JWT 身份验证(JWT authentication bypass via kid header path traversal)
1 | 通过kid参数注入自签名JWT |
1、开启实验环境,使用账号登录抓包
2、将访问目录改为/admin,然后尝试访问,可以看到服务器返回401 Unauthorized,代表身份验证未通过
3、生成对称密钥
4、将生成的属性值替换k
为 Base64 编码的空字节 ( AA==
)。(这只是一种解决方法,因为 JWT Editor插件不允许使用空字符串签署令牌)
5、在 JWT 的 头部,将kid
参数的值更改为指向文件的/dev/null
序列:
1 | ../../../dev/null |
6、然后使用生成的对称密钥对JWT重新签名
7、重新签名之后发送请求,就可以成功访问管理员面板了
8、然后使用管理员权限删除指定的用户即可
如何防御JWT攻击
1 | 来自BurpSuite的建议: |