pyjwt中,假如修改这个token的荷载中的exp值,再生成荷载,那jwt能否检测到的实验
JWT(JSON Web Token)的签名机制确保了令牌的完整性和真实性。如果你修改了 JWT 的荷载(payload)中的 exp
值或其他任何字段,然后尝试使用原始的签名,JWT 的验证将失败,因为签名不再匹配修改后的荷载。
示例:验证修改后的 JWT
假设你有一个原始的 JWT 令牌:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMjMsInVzZXJuYW1lIjoiemhvdWNsIiwiZXhwIjoxNzQzMDg1MDc0fQ.your_signature_here
如果你修改了荷载中的 exp
值,例如将其改为 1743086137
,新的荷载部分将变为:
eyJ1c2VyX2lkIjoxMjMsInVzZXJuYW1lIjoiemhvdWNsIiwiZXhwIjoxNzQzMDg2MTM3fQ
如果你尝试将修改后的荷载与原始签名组合成一个新的令牌:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMjMsInVzZXJuYW1lIjoiemhvdWNsIiwiZXhwIjoxNzQzMDg2MTM3fQ.your_signature_here
这个令牌将无法通过验证,因为签名部分不再匹配荷载部分。
Python 验证代码
以下是使用 Python 的 PyJWT
库验证 JWT 的示例代码:
import jwt
# JWT 配置
SECRET_KEY = "your-secret-key" # 替换为你的密钥
ALGORITHM = "HS256"
# 示例:验证 JWT 签名
def verify_jwt(token: str):
try:
# 解码并验证 JWT 签名
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
return payload
except jwt.ExpiredSignatureError:
print("Token has expired")
return None
except jwt.InvalidTokenError:
print("Invalid token")
return None
# 示例令牌(修改后的)
token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMjMsInVzZXJuYW1lIjoiemhvdWNsIiwiZXhwIjoxNzQzMDg2MTM3fQ.qUJTeL3QE487ozO-d6sJBhfQ19fcRNLW1KMqidEV7bo"
# 验证令牌
decoded_payload = verify_jwt(token)
if decoded_payload:
print("Decoded payload:", decoded_payload)
else:
print("Token verification failed")
输出结果
运行上述代码后,输出结果为:
Invalid token
Token verification failed
原因解释
-
签名不匹配:
- JWT 的签名部分是基于原始的荷载和头部生成的。如果你修改了荷载中的任何字段(如
exp
),签名将不再有效。
- JWT 的签名部分是基于原始的荷载和头部生成的。如果你修改了荷载中的任何字段(如
-
验证失败:
- 在验证过程中,
jwt.decode()
方法会重新计算签名并将其与令牌中的签名进行比较。如果两者不匹配,将抛出InvalidTokenError
异常。
- 在验证过程中,
总结
JWT 的签名机制确保了令牌的完整性和真实性。任何对荷载或头部的修改都会导致签名不匹配,从而在验证时被检测到。这就是为什么即使你修改了 exp
值,JWT 也能检测到并拒绝验证的原因。
最后的实验结果
playload为:
{
"user_id": 123,
"username": "zhoucl",
"exp": 1743086137
}
经过pyjwt生成的token的playload:eyJ1c2VyX2lkIjoxMjMsInVzZXJuYW1lIjoiemhvdWNsIiwiZXhwIjoxNzQzMDg2MTM3fQ
完整token:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMjMsInVzZXJuYW1lIjoiemhvdWNsIiwiZXhwIjoxNzQzMDg2MTM3fQ.qUJTeL3QE487ozO-d6sJBhfQ19fcRNLW1KMqidEV7bo
仅仅修改playload中exp中的值:
{
"user_id": 123,
"username": "zhoucl",
"exp": 1743096137
}
替换中间playload:eyJ1c2VyX2lkIjoxMjMsInVzZXJuYW1lIjoiemhvdWNsIiwiZXhwIjoxNzQzMDk2MTM3fQ
但沿用原来的签名:qUJTeL3QE487ozO-d6sJBhfQ19fcRNLW1KMqidEV7bo
经过hack后的token:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMjMsInVzZXJuYW1lIjoiemhvdWNsIiwiZXhwIjoxNzQzMDk2MTM3fQ.qUJTeL3QE487ozO-d6sJBhfQ19fcRNLW1KMqidEV7bo
pyjwt正常加密hack的playload的token值:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMjMsInVzZXJuYW1lIjoiemhvdWNsIiwiZXhwIjoxNzQzMDk2MTM3fQ.lNzt3YebtF-TpviYvyTK0396V-5hIeNZD9FIB2SR_Ps
签名为:lNzt3YebtF-TpviYvyTK0396V-5hIeNZD9FIB2SR_Ps
总结:playload是否被修改,该算法是比对最后的签名值:
hack playload:eyJ1c2VyX2lkIjoxMjMsInVzZXJuYW1lIjoiemhvdWNsIiwiZXhwIjoxNzQzMDk2MTM3fQ
原来 playload:eyJ1c2VyX2lkIjoxMjMsInVzZXJuYW1lIjoiemhvdWNsIiwiZXhwIjoxNzQzMDg2MTM3fQ
hack playload签名:lNzt3YebtF-TpviYvyTK0396V-5hIeNZD9FIB2SR_Ps
原来 playload签名:qUJTeL3QE487ozO-d6sJBhfQ19fcRNLW1KMqidEV7bo