Web攻防-身份验证篇&JWT令牌&空密钥&未签名&密钥爆破&JWK&JWU&KID&算法替换
#JWT
JSON Web Token(JWT)。它遵循JSON格式,将用户信息加密到token里,服务器不保存任何用户信息,只保存密钥信息,通过使用特定加密算法验证token,通过token验证用户身份。基于token的身份验证可以替代传统的cookie+session身份验证方法。这使得JWT成为高度分布式网站的热门选择,在这些网站中,用户需要与多个后端服务器无缝交互。
-JWT识别
1、标头(Header)
Header是JWT的第一个部分,是一个JSON对象,主要声明了JWT的签名算法,如"HS256”、"RS256"等,以及其他可选参数,如"kid"、"jku"、"x5u"等
alg字段通常用于表示加密采用的算法。如"HS256"、"RS256"等
typ字段通常用于表示类型
还有一些其他可选参数,如"kid"、"jku"、"jwk"等
HS256(HMAC-SHA256):
对称加密算法,使用同一个密钥(Secret Key)进行签名和验证。
密钥必须严格保密,任何持有密钥的人都可以生成或验证令牌。
密钥通常是一个随机字符串(如
secret-key-123
)。RS256(RSA-SHA256):
私钥(Private Key)用于签名(仅由签发方持有)。
公钥(Public Key)用于验证(可公开分发)。
非对称加密算法,使用公私钥对:
安全性更高,因为公钥无法用于伪造签名。
2、有效载荷(Payload)
Payload是JWT的第二个部分,这是一个JSON对象,主要承载了各种声明并传递明文数据,用于存储用户的信息,如id、用户名、角色、令牌生成时间和其他自定义声明。
iss:该字段表示jwt的签发者。
sub:该jwt面向的用户。
aud:jwt的接收方。
exp:jwt的过期时间,通常来说是一个时间戳。
iat:jwt的签发时间,常来说是一个时间戳。
jti:此jwt的唯一标识。通常用于解决请求中的重放攻击。该字段在大多数地方没有被提及或使用。因为使用此字段就意味着必须要在服务器维护一张jti表, 当客户端携带jwt访问的时候需要在jti表中查找这个唯一标识是否被使用过。使用这种方式防止重放攻击似乎让jwt有点怪怪的感觉, 毕竟jwt所宣称的优点就是无状态访问
3、签名(Signature)
Signature是对Header和Payload进行签名,具体是用什么加密方式写在Header的alg 中。同时拥有该部分的JWT被称为JWS,也就是签了名的JWT。
对Header和Payload进行签名,具体是用什么加密方式写在Header的alg中。
同时拥有该部分的JWT被称为JWS,也就是签了名的JWT。
第一部分:对 JSON 的头部做 base64 编码处理得到
第二部分:对 JSON 类型的 payload 做 base64 编码处理得到
第三部分:分别对头部和载荷做base64编码,并使用.拼接起来
使用头部声明的加密方式,对base64编码前两部分合并的结果加盐加密处理,作为JWT
识别检测利用项目:
BURP插件:Hae&JSON Web Tokens&JWT Editor
https://jwt.io/
https://github.com/z-bool/Venom-JWT
https://github.com/ticarpi/jwt_tool
https://github.com/wallarm/jwt-secrets -----这是jwt爆破密钥
https://github.com/CompassSecurity/jwt-scanner
jwk(JSON Web Key):提供一个表示密钥的嵌入式JSON对象。
jku(JSON Web Key Set URL):提供一个URL,服务器可以从中获取一组包含正确密钥的密钥。
kid(Key ID):提供一个ID,在有多个密钥可供选择的情况下,服务器可以使用该ID来识别正确的密钥。根据密钥的格式可能还有一个匹配的kid参数。
参考:blog.csdn.net/weixin_44288604/article/details/128562796
1、实验室:通过未验证的签名绕过JWT身份验证
2、实验室:通过有缺陷的签名验证绕过JWT身份验证
3、实验室:通过弱签名密钥绕过JWT身份验证
4、实验室:通过jwk标头注入绕过JWT身份验证
JWK 基本结构
一个典型的 JWK 包含密钥的元数据和密钥材料本身。例如:
HS256 的对称密钥 (JWK)
{ "kty": "oct", "alg": "HS256", "k": "GawgguFyGrWKav7AX4VKUg", // Base64 编码的密钥 "kid": "my-hmac-key-1"}
RS256 的非对称密钥对 (JWK)
// 公钥{ "kty": "RSA", "alg": "RS256", "n": "modulus_value...", // RSA 公钥模数 (Base64URL) "e": "AQAB", // RSA 公钥指数 (通常 65537) "kid": "my-rsa-key-1"}// 私钥(通常不公开){ "kty": "RSA", "alg": "RS256", "n": "modulus_value...", "e": "AQAB", "d": "private_exponent...", // 私钥指数 "p": "prime1...", // RSA 质数 p "q": "prime2...", // RSA 质数 q "kid": "my-rsa-key-1"}
5、实验室:通过jku标头注入绕过JWT身份验证
JKU (jku
) 是 JWT (JSON Web Token) 头部的一个可选字段,用于指定一个 JWK Set (JSON Web Key Set) 的 URL,客户端可以通过该 URL 动态获取公钥来验证 JWT 签名。JKU 主要用于非对称加密(如 RS256、ES256)场景,使密钥管理更灵活,但也可能被恶意利用。
JKU 的安全风险与攻击方式
由于 jku
允许动态指定密钥来源,攻击者可能利用它进行 JWT 伪造。
攻击 1:恶意 JWKS 端点劫持
攻击方式:
攻击者伪造一个 JWT,并将
jku
指向自己控制的服务器(如https://attacker.com/malicious-jwks.json
)。如果服务端未校验
jku
的可信性,会使用攻击者的公钥验证 JWT,导致伪造成功。防御措施:
白名单校验:只允许受信任的域名(如
https://auth.example.com/.well-known/jwks.json
)。HTTPS 强制:确保
jku
使用 HTTPS,防止中间人攻击。固定证书:使用证书固定(Certificate Pinning)防止伪造。
攻击 2:SSRF (Server-Side Request Forgery)
攻击方式:
如果 JWT 验证服务会访问
jku
URL,攻击者可构造恶意 URL 扫描内网(如http://169.254.169.254/metadata
)。防御措施:
限制
jku
的访问范围(如只允许公网域名)。禁用对内部 IP 的请求。
攻击 3:JWKS 缓存投毒
攻击方式:
攻击者短暂控制
jku
指向的 JWKS,使客户端缓存恶意公钥。防御措施:
设置合理的缓存时间(如 5 分钟)。
强制重新获取 JWKS(如每次验证 JWT 时都请求最新版本)。
攻击 4:算法混淆 + JKU 劫持
攻击方式:
即使服务端强制使用
RS256
,攻击者仍可构造jku
指向一个包含 HS256 密钥的 JWKS,并让服务端误用对称加密验证。防御措施:
强制校验 JWKS 中的
alg
是否符合预期(如只允许RS256
)。在代码中显式指定算法:
# 错误:未校验算法decoded = jwt.decode(token, key_from_jku)# 正确:强制使用 RS256decoded = jwt.decode(token, key_from_jku, algorithms=["RS256"])
6、实验室:通过kid头路径遍历绕过JWT身份验证
7、算法混淆
-Web349(公钥私钥泄露)
pip install PyJWT==1.7.1
import jwt
public = open('private.key', 'r').read()
payload={"user":"admin"}
print(jwt.encode(payload, key=public, algorithm='RS256'))
-Web350(密钥混淆攻击RS256=>HS256)
将RS256算法改为HS256(非对称密码算法=>对称密码算法)
HS256算法使用密钥为所有消息进行签名和验证。
而RS256算法则使用私钥对消息进行签名并使用公钥进行身份验证。
var jwt = require('jsonwebtoken');
var fs = require('fs');
var privateKey = fs.readFileSync('./public.key');
var token = jwt.sign({ user: 'admin' }, privateKey, { algorithm: 'HS256' });
console.log(token)
8、某个测试目标
参考:https://mp.weixin.qq.com/s/obiU3BaFoZ7272z2vS0QgQ
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjo0MDcyNjE1MzE0fQ.mwI2P1j8CIvhxBKFvcyU7TNLBeuFtiUM1mPrKanF1w4
Content-Type: application/x-www-form-urlencoded
db=sample&q=show users
复盘:
https://mp.weixin.qq.com/s/ITVFuQpA8OCIRj4wW-peAA
https://mp.weixin.qq.com/s/xuY1oTwFcM1pyiql0U3NPQ
https://mp.weixin.qq.com/s/AVW8DsnLiviopeJYQYKC3A
https://mp.weixin.qq.com/s/st0xma6KoRbo1NUp9rtZhw
https://mp.weixin.qq.com/s/9OL5jZK7S1MiEUb8Q_F1Pw
首先找到需要JWT鉴权后才能访问的页面,如个人资料页面,将请求重放测试:
1)未授权访问:删除Token后仍然可以正常响应对应页面
2)敏感信息泄露:通过JWt.io解密出Payload后查看其中是否包含敏感信息,如弱加密的密码等
3)破解密钥+越权访问:通过JWT.io解密出Payload部分内容,通过空加密算法或密钥爆破等方式实现重新签发Token并修改Payload部分内容,重放请求包,观察响应包是否能够越权查看其他用户资料
4)检查Token时效性:解密查看payload中是否有exp字段键值对(Token过期时间),等待过期时间后再次使用该Token发送请求,若正常响应则存在Token不过期
5)通过页面回显进行探测:如修改Payload中键值对后页面报错信息是否存在注入,payload中kid字段的目录遍历问题与sql注入问题