一、概述
在 JWT 安全性总结 中提到了JWT的三个组成部分,包括header、claims以及signature,其中Signature是一个签名的部分,其计算方法为:HMACSHA256(base64UrlEncode(header)+"."+base64UrlEncode(payload),secret) ,即header的BASE64编码、点号、Clamis的BASE64编码以及将secret作为盐值,以前面申明的HASH算法进行计算,得到的一个值,该值具有不可逆性。本篇博客用Python实现一下JWT的具体生成及验证。
二、准备
从www.jwt.io取一个JWT令牌,密码设置为hello,我们得到JWT为eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.ElsKKULlzGtesThefMuj2_a6KIY9L5i2zDrBLHV-e0M,这里注意signature部分,下面我们要通过代码实现计算,看得到的signature是否与网站上生成的一致。
三、生成JWT
(一)自己通过Python代码实现
直接上代码:
#先将token放在这里,后面生成新的token后可以进行对比
tokenold = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.ElsKKULlzGtesThefMuj2_a6KIY9L5i2zDrBLHV-e0M"
header = {
"alg": "HS256",
"typ": "JWT"
}
payload = {
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}
signature = ''
'''
根据JWT生成的原理,通过代码实现JWT的生成以及验证
'''
'''
JWT即Json Web Token,在JSON格式中通常为了格式化,在每个部分冒号(“:”)或者逗号(“,”)前后可能存在一些空格,这里需要先将无用的空格去掉,避免影响结果生成。
'''
def remove_spaces(token):
token = json.dumps(token, separators=(',', ':'))
return token
'''
使用hmac模块的new方法,调用相应的函数,生成signature签名
这里写一个方法,传入待签名的data以及签名的密钥key
返回签名值
'''
def getSha256(data, key):
key = key.encode("utf-8")
data = data.encode("utf-8")
sign = hmac.new(key, data, digestmod='sha256').digest()
return sign
'''
根据JWT明文内容,进行JWT签名,并且生成完整的JWT
'''
def jwtGenerate1():
'''
1、对header/payload部分去掉多余的空格
2、进行BASE64编码,通过decode去掉结果中的"b"
3、将结果中的等号去掉
'''
headerBase64Encode
= base64.b64encode(str(remove_spaces(header)).encode("utf-8")).decode().replace("=", "")
payloadBase64Encode =
base64.b64encode(str(remove_spaces(payload)).encode("utf-8")).decode().replace("=", "")
#
print(headerBase64Encode)
'''
4、将header的BASE64编码、点号、payload的BASE64编码组合,得到待签名的数据
'''
data = str(headerBase64Encode)
+ "." + str(payloadBase64Encode)
# print("data:
" + data)
'''
5、将准备好的data以及密钥值传入前面定义的函数getsha256
6、将返回的结果进行BASE64编码,去掉其中的等号
'''
signature = str(base64.b64encode(getSha256(data, "hello")).decode()).replace("=", "")
'''
7、组合所有得到的BASE64编码,然后将其中的"/"以及“_"分别替换为"+"以及"-",得到最终的token值
'''
token = str(headerBase64Encode
+ "." + payloadBase64Encode + "." +
signature).replace("/", "_").replace("+", "-")
print("header:
" + str(headerBase64Encode))
print("payload:
" + payloadBase64Encode)
print("signature:
" + signature)
print("token:
" + token)
if tokenold ==
token:
print("ok!")
运行一下看结果:
Signature值为ElsKKULlzGtesThefMuj2_a6KIY9L5i2zDrBLHV-e0M,与网站上的一致。
(二)通过jwt模块实现
代码实现:
'''
使用pyjwt库进行jwt 生成以及jwt的验证过程,该方法使用简单
'''
def jwtGenerate2():
'''
使用jwt的encode方法,直接生成token,key为签名密钥
'''
token = jwt.encode(payload=payload, key="hello", algorithm='HS256', headers=header)
print(token)
运行得到结果:
可以看到结果是一样的。
四、校验JWT
(一)自己通过Python代码实现
代码实现:
'''
根据JWT token进行解码,判断签名的解密是否正确
'''
def jwtCheck1():
'''
1、分别获取到BASE64编码后的header、payload、signature
'''
headerBase64Encode = tokenold.split(".")[0]
payloadBase64Encode = tokenold.split(".")[1]
signatureBase64Encode = tokenold.split(".")[2]
'''
2、将编码后的header、点号、payload组合,得到待签名的数据
'''
data = headerBase64Encode + "." + payloadBase64Encode
'''
3、传入签名密钥,对数据进行签名,得到signature的BASE64编码
4、注意要将其中的“=”、“/”、“+”分别替换为无、“_”、“-”
这里我使用的密钥为hello
'''
signature = str(base64.b64encode(getSha256(data, "hello
")).decode()).replace("=", "").replace("/", "_").replace("+", "-")
print("The new signature is: " + signature)
print("The old signature is: " + signatureBase64Encode)
'''
5、将原始签名数据与自己计算得到的签名数据进行比较,如果相同,则签名密钥正确
'''
if signatureBase64Encode == signature:
print("Signature Verified !")
else:
print("Signature Faied !")
运行得到结果:
修改密钥为hao123再试一下:
signature = str(base64.b64encode(getSha256(data, "hao123")).decode()).replace("=", "").replace("/", "_").replace("+", "-")
结果:
可以看到,密钥修改了,导致签名校验失败。
(二)通过jwt模块实现
代码如下:
def jwtCheck2():
'''
使用jwt的decode方法,传入密钥,如果密钥正确,则返回payload
如果密钥不正确,抛出异常,签名验证失败
'''
try:
signatureNew = jwt.decode(tokenold, "hao123", algorithms=['HS256'], verify=True)
print(signatureNew)
except Exception as e:
print(e)
密钥为hao123时,校验失败:
密钥为hello时,校验成功:
五、总结扩展
上面描述了两种方式用于JWT的生成与校验,第一种方式是自身通过代码去实现,第二种方式是通过模块去实现,结果一样,不过第一种方式让我更加深刻理解了原理。
既然实现了JWT的校验,那么只需要将密钥作为变量,通过循环即可实现JWT的暴破,这里就不再体现了。
标签:验证,Python,JWT,token,密钥,signature,print,data From: https://blog.51cto.com/u_9652359/6351659