JWT, token的设计和验证

JWT (json web token)是一种http request主流加密方式,相比传统的token,JWT的优势在于无状态传播,不需要存储到数据库,就可以实现安全令牌验证,缺点是一经签发,exp失效前令牌都会一直有效,此认证状态无法更改。

JWT无法被破解的关键,是在其第三部分签名里的哈希加密中的盐值。

由于哈希加密是无法直接解密的,所以jwt实际上只是重复使用加密的过程进行验证而已。

具体过程

一、头部 (head)

包含了具体的算法,如HS256 HS512等,typ类型:JWT,通常写法

二、负载(payload)

包含了关键信息,包含用户名,过期日期,其他自定义键值等

三、签名(sign)

将一二部分进行base64加密后的结果再进行哈希加盐加密,处理后的最后字符串为关键验证信息。

注意:base64加密方式中原表的“/“,"+","="这三个字符,在进行JWT加密时通用的base64url加密,在加密过程中将其会替换成“-”,“_”,并去掉“=”。

 

 

具体加密过程:

将头部字典变为json格式(json.dumps),并将其分割符号变为“,”与“:”,去掉空格紧凑分割

将头部进行base64url加密,再去掉里面的“=”,

 

将负载中的exp添加键值:即为过期日期,格式为int

将其同样处理为json格式,再进行base64url加密

 

将头部和负载相连,中间用"."符号连接。

检查盐值,如果盐里面有字符串,将其encode为二进制字节串

对连接好的头部负载进行哈希加密,输入盐值,方法(hmac.new(盐值,签名,digestmod='SHA256'))

将处理好的sign再进行签名化处理  (x.digest()方法)

为其再次进行base64加密处理,得到最终的签名令牌

 

最后,将头部、负载、签名再使用b“.”连接起来,就得到完全的JWT了,这就是其完整处理过程

 

 

 

代码:

import copy
import hmac
import json
import base64
import time


class Jwt():
    def __init__(self):
        pass
    @staticmethod
    def encode(payload, key, exp=300):
        #create header
        header = {'alg':'HS256','typ':'JWT'}
        header_j = json.dumps(header, separators=(',',':'),sort_keys=True)

        header_bs = Jwt.b64encode(
            header_j.encode())
        payload = copy.deepcopy(payload)
        payload['exp'] = int(time.time()) + exp
        payload_j = json.dumps(payload, separators=(',',':'), sort_keys=True)

        payload_bs = Jwt.b64encode(payload_j.encode())

        to_sign_str = header_bs + b'.' + payload_bs

        if isinstance(key, str):
            key = key.encode()
        hmac_obj = hmac.new(key,to_sign_str,
                            digestmod='SHA256')
        sign = hmac_obj.digest()
        sign_bs = Jwt.b64encode(sign)
        return header_bs + b'.' + payload_bs + b'.' + sign_bs

    @staticmethod
    def b64encode(s):
        return base64.urlsafe_b64encode(s).replace(b'=',b'')

    @staticmethod
    def b64decode(s):
        mod = len(s) % 4
        s += b'='*(4-mod)
        return base64.urlsafe_b64decode(s)
    @staticmethod
    def decode(token,key):
        header_bs,payload_bs,sign = token.split(b'.')
        if isinstance(key, str):
            key = key.encode()
        hm = hmac.new(key, header_bs + b'.' + payload_bs,digestmod='SHA256')
        new_sign = Jwt.b64encode(hm.digest())
        if sign != new_sign:
            raise JwtSignError('Your token is not true')

        payload_j = Jwt.b64decode(payload_bs)
        print(type(payload_j))
        payload = json.loads(payload_j)
        exp = payload['exp']
        now = time.time()
        if now > exp:
            raise JwtSignError('Your token is valid')
        return payload
class JwtSignError(Exception):
    def __init__(self,error_msg):
        self.error = error_msg
    def __str__(self):
        return '<JwtError error %s>' %(self.error)

if __name__ == "__main__":
    res = Jwt.encode({'username':'lxxx'},'abcdef1234',1)
    print(Jwt.decode(res,'abcdef1234'))

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章