0
点赞
收藏
分享

微信扫一扫

Python实现JWT的生成及验证

少_游 2023-05-25 阅读 80

一、概述

       在 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是否与网站上生成的一致。

Python实现JWT的生成及验证_jwt

三、生成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!")

运行一下看结果:

Python实现JWT的生成及验证_jwt_02

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)

运行得到结果:

Python实现JWT的生成及验证_BASE64_03

可以看到结果是一样的。

四、校验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 !")

运行得到结果:

Python实现JWT的生成及验证_Python_04

修改密钥为hao123再试一下:

signature = str(base64.b64encode(getSha256(data, "hao123")).decode()).replace("=", "").replace("/", "_").replace("+", "-")

结果:

Python实现JWT的生成及验证_BASE64_05

可以看到,密钥修改了,导致签名校验失败。

(二)通过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时,校验失败:

Python实现JWT的生成及验证_BASE64_06

密钥为hello时,校验成功:

Python实现JWT的生成及验证_Python_07

五、总结扩展

     上面描述了两种方式用于JWT的生成与校验,第一种方式是自身通过代码去实现,第二种方式是通过模块去实现,结果一样,不过第一种方式让我更加深刻理解了原理。

      既然实现了JWT的校验,那么只需要将密钥作为变量,通过循环即可实现JWT的暴破,这里就不再体现了。

举报

相关推荐

0 条评论