zoukankan      html  css  js  c++  java
  • python中的JWT

    为了解决Http无状态问题,产生了cookie和session技术。

     传统的session技术解决了无状态问题,但是不能防止客户端的篡改,而且对于服务端要保存session,在数据量较大,业务规模增加时,还要解决多台服务器之间的session共享问题,使用redis或者memcached等方案。

    产生可JWT技术可以解决用户篡改问题,服务器端产生的标识,使用算法加密,对标识签名。

    再次收到服务器端的标识,就要检查签名。

    这种方法在加密解密时,会消耗cpu计算资源,而且无法让浏览器自己检查过期数据,并且删除。

    下边我将尝试解释一下jwt防篡改的原理。

    JWT 全称(Json WEB Token)是一种采用Json方式安装传输信息的方式。

    python下的实现的pyjwt

    文档 : https://pyjwt.readthedocs.io/en/latest/

    安装 : pip install pyjwt

    先看以下代码:

    import jwt
    
    key = "secret"
    token = jwt.encode({"test": "100"},key,"HS256")
    print(token)
    header,payload,signature = token.split(b".")
    print(header)
    print(payload)
    print(signature)

    显示

    b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0ZXN0IjoiMTAwIn0.p2dBskystmxOlIXrBCowu6DPcWQbRrZMT3hJV7iMY-8'
    b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9'
    b'eyJ0ZXN0IjoiMTAwIn0'
    b'p2dBskystmxOlIXrBCowu6DPcWQbRrZMT3hJV7iMY-8'

    可以知道JWT由3段由点分割的部分组成。

    它使用的编码是base64编码,我们导入以下

    import jwt
    
    key = "secret"
    token = jwt.encode({"test": "100"},key,"HS256")
    print(token)
    header,payload,signature = token.split(b".")
    
    import base64
    
    def equal(b: bytes):
        """用来补齐被JWT去掉的等号"""
        rest = len(b) % 4
        return b + b'=' * rest
    
    print("header=",base64.urlsafe_b64decode(equal(header)))
    print("payout=", base64.urlsafe_b64decode(equal(payload)))
    print("signature", base64.urlsafe_b64decode(equal(signature)))

    显示:

    header= b'{"typ":"JWT","alg":"HS256"}'
    payout= b'{"test":"100"}'
    signature b'xa7gAxb2Lxacxb6lNx94x85xebx04*0xbbxa0xcfqdx1bFxb6LOxIWxb8x8ccxef'

    可以看到,JWT中传输的token内容由三部分组成

    • header 是由数据类型和加密算法组成
    • payload 是传输的数据部分,
    • signature 部分就时签名,是由前两部分和加密算法实现的,看以下代码

    下边是源码中的一部分,signing_input就是将前两部分转为JSON格式,再使用base64编码,连接起来,传入下边的方法中,alg_obj是方法,key是预处理key

    signing_input = b'.'.join(segments)
            try:
                alg_obj = self._algorithms[algorithm]
                key = alg_obj.prepare_key(key)
                signature = alg_obj.sign(signing_input, key)

    我们模仿一下,可得

    import jwt
    
    # Create your tests here.
    
    key = "secret"
    token = jwt.encode({"test": "100"},key,"HS256")
    header,payload,signature = token.split(b".")
    print(signature)
    
    import base64
    
    # def equal(b: bytes):
    #     """用来补齐被JWT去掉的等号"""
    #     rest = len(b) % 4
    #     return b + b'=' * rest
    
    # print("header=",base64.urlsafe_b64decode(equal(header)))
    # print("payout=", base64.urlsafe_b64decode(equal(payload)))
    # print("signature", base64.urlsafe_b64decode(equal(signature)))
    
    from jwt import algorithms
    alg = algorithms.get_default_algorithms()["HS256"]
    newkey = alg.prepare_key(key)
    signature_input = b".".join([header,payload])
    signature = alg.sign(signature_input,newkey)
    
    print(base64.urlsafe_b64encode(signature))

    显示,可以看到

    b'p2dBskystmxOlIXrBCowu6DPcWQbRrZMT3hJV7iMY-8'
    b'p2dBskystmxOlIXrBCowu6DPcWQbRrZMT3hJV7iMY-8='

    所以在密码相同时,传输相同的信息,得到的值是一样的。

    密码要足够强,且要足够安全。可以在测试下改变内容,看签名会不会改变。

    import jwt
    
    # Create your tests here.
    
    key = "secret"
    token = jwt.encode({"test": "100"},key,"HS256")
    header,payload,signature = token.split(b".")
    print(signature)
    
    import base64
    
    # def equal(b: bytes):
    #     """用来补齐被JWT去掉的等号"""
    #     rest = len(b) % 4
    #     return b + b'=' * rest
    
    # print("header=",base64.urlsafe_b64decode(equal(header)))
    # print("payout=", base64.urlsafe_b64decode(equal(payload)))
    # print("signature", base64.urlsafe_b64decode(equal(signature)))
    token = jwt.encode({"test": "1000"},key,"HS256") # 改变payload内容
    header,payload,signature = token.split(b".")
    
    from jwt import algorithms
    alg = algorithms.get_default_algorithms()["HS256"]
    newkey = alg.prepare_key(key)
    signature_input = b".".join([header,payload])
    signature = alg.sign(signature_input,newkey)
    
    print(base64.urlsafe_b64encode(signature))

    可以看到签名变了

    b'p2dBskystmxOlIXrBCowu6DPcWQbRrZMT3hJV7iMY-8'
    b'uCmPr1eOuLz8IDLQfN8t_DsyrB9PYfdvdueeHSBWN04='

    经过以上测试,可以知道,数据在使用JWT传输时,是明文传输的,注意不要传输敏感数据。

    JWT的防篡改还可以使用公钥,私钥,来防止用户被劫持的可能性。

    在用户登陆成功后可以使用JWT技术,登录后给用户JWT,用户发请求时加上jwt,服务器校验签名,通过就允许访问,在单点登陆时广泛应用。

  • 相关阅读:
    35.python之事件驱动模型
    33.python之操作系统,进程,线程
    VRChat之blender2.8版本设置
    VRChat模型制作及上传总篇(201912)
    linux常用指令
    java基础File的简单使用记录
    java 通过实现Comparable接口使用Collections.sort排序 及 利用set的特性对 list 进行去重
    [转发] java字符串-编码转换-工具类
    ssh服务不能远程时,使用telnet远程登录
    java中List遍历删除元素相关做法和注意事项
  • 原文地址:https://www.cnblogs.com/rprp789/p/10017781.html
Copyright © 2011-2022 走看看