session与token

1. base64

  Base64是一种用于将二进制数据编码为文本的编码方案,它使用ASCII字符串格式来表示二进制数据。Base64常用于在只能处理ASCII字符的系统上传输数据,如电子邮件系统、web服务器以及编码媒体文件。在Base64中,每个字符代表6个数据位,因此可以将3个字节的二进制数据编码为4个字符。这种编码方案被用于多种用途。具体的编码方式入下:

 

具体编码步骤如下:

  1.将字符串拆成每三个字符一组

  2.计算每一个字符对应的ASCII码的二进制

  3.将8位二进制码,按照每6位一组重新分组,不足6位的后面补0.

  4.计算对应的十进制编码

  5.按照base64表,查看对应的字符。

  如果编码不足3个ASCII字符(3*8=24)的长度,多余的部分补0到6个,最后面没有的补base字符为'='字符。具体如下:

  也就是说base64字符串个数是4的倍数。关于base64的主要方法如下:

2. 代码

"""
base64是一种编码技术
base64所有方法的参数和结果都是字节串
"""
import base64
#1.编码:明文---》base64
r1=base64.b64encode(b"wa")
  #print(r1)#b'd2E='
print(r1.decode())#d2E=

username="wangxi"
r2=base64.b64encode(username.encode())#username.encode()变为字节串
print(r2)#b'd2FuZ3hp'
#2.解码
r22=base64.b64decode(r2)
print(r22)#b'wangxi'

  使用base64,可以将明文按照base64的特定规则转换为base64编码,但是仍然能反向破解。对于真正的不可逆向的加密得使用md5、sha256等算法。

3. session

  在Web开发中,Session是一种用于跟踪用户会话的机制,以实现用户在不同请求之间的状态保持和数据共享。它通过在服务器端存储和管理用户相关数据,并通过一个唯一的标识符将会话与用户关联起来。工作原理如下:

  1. 用户在浏览器中发送一个HTTP请求到服务器,并携带一个唯一的标识符,通常称为Session ID。
  2. 服务器接收到请求后,根据Session ID查找关联的Session数据。如果找到了,则表示该用户存在会话,可以获取和修改Session中的数据。如果没有找到,则表示该用户是新用户,需要创建一个新的Session,并生成一个唯一的Session ID,同时会创建一个特殊的cookie。
  3. 服务器将Session ID作为Cookie的一部分发送给浏览器。浏览器在后续的请求中会自动将这个Cookie携带上来。
  4. 用户的后续请求在Cookie中携带了Session ID后,服务器会根据Session ID和服务器内存中存放的Session ID进行比对,获取关联的Session数据,并对其进行操作。
  5. 当用户会话结束(如关闭浏览器或超过Session过期时间)时,服务器会销毁该会话,删除对应的Session数据。

通过Session,Web应用可以实现以下功能:

  • 跟踪用户的登录状态,实现用户认证和授权。
  • 存储用户的个性化信息,如首选语言、主题等。
  • 在多个页面之间共享数据,如购物车内容、表单数据等。
  • 限制用户的访问权限,如设置Session超时时间等。

  需要注意的是,Session数据存储在服务器端,对服务器的存储和处理能力有一定要求。同时,Session ID需要保持安全,以防止会话劫持等安全问题。

  这里,给出Session与Cookie的对比。

4. 散列加密算法。

  4.1 SHA-256

 

    SHA-256(Secure Hash Algorithm-256)它是一种安全散列加密算法,这里不过多介绍。其有三大特点:定长输出、不可逆、雪崩。

 

from hashlib import sha256
s = sha256() # 1.创建sha256对象
s.update(b'abcd') # 2.添加欲hash的内容,类型为 bytes
hex_result = s.hexdigest() # 3.十六进制结果(十六进制,用于存储)
print(hex_result)#88d4266fd4e6338d13b......
print(len(hex_result))#64

s.update(b'abc')#减少一个d会造成与abcd加密得结果巨大不同,’雪崩效果‘
hex_result = s.hexdigest()
print(hex_result)#8a50a4422d673f463f8e......
print(len(hex_result))#64

 

  因为加密不可逆,无法将结果转换为明文,所以很安全。

  4.2.HMAC-SHA256

  HMAC-SHA256(Hash-basedMessageAuthenticationCode)是一种通过特别计算方式之后产生的消息认证码,使用散列算法同时结合一个加密密钥。它可以用来保证数据的完整性,同时可以用来作某个消息的身份验证。

import hmac
# 1. 生成hmac对象
# 参数1:密钥key,bytes类型,
# 参数2:欲加密的串,bytes类型
# 参数3:hmac的算法,指定为SHA256
key = b'123456'
string = b'{"username":"chaogege"}'
h = hmac.new(key, string, digestmod='SHA256')
result = h.hexdigest() # 获取最终结果
print(result)#6ae909d8d5f825...
print(len(result))#64

  除了上面介绍的哈希加密算法之外,还有md5等加密算法。

5. token

  token在计算机身份认证中是令牌(临时)的意思,相对于session而言,其不需要存储用户信息,只需要对用户传过来的token信息进行计算就能达到身份认证的效果,而且防篡改能力强。为了减轻服务器频繁查询的压力,往往采用token作为令牌进行会话认证。

  5.1 JWT(json-web-token)

  JWTJSON Web Token)是一种用于验证和在网络应用之间传递声明(claims)的开放标准(RFC 7519)。它通常用作身份验证(Authentication)和授权(Authorization)的令牌(Token)。

  JWT由三个部分组成,每个部分之间使用点号(.)分隔:

  Header(头部):包含了标识这个JWT的类型和使用的签名算法的信息。格式如下:{"alg":"HS256","typ":"JWT"}alg代表要使用的算法,typ是固定的大写JWT。

 

  Payload(载荷):包含了实际的声明(claims),例如用户的ID、权限等信息。主要常用格式如下:{"exp":设置token的过期的时间戳,"":"私有key":"值"}

 

  Signature(签名):使用指定的算法对前两个部分进行签名,以确保JWT的完整性和真实性。以下用 HS256为例sign =hmac.new(自定义的key ,

  base64后的header + b'.' + base64后的payload,digestmod="SHA256")

 

  JWT的基本工作流程如下:

  用户使用用户名和密码进行身份验证。

  服务器验证用户的凭据,并生成一个JWT作为其身份验证的令牌。

  服务器将JWT发送给客户端,并将其存储在Cookie或本地存储中。

  客户端在后续的请求中将JWT发送到服务器,以便进行授权和身份验证。

  服务器验证JWT的合法性和完整性,并根据其中的声明进行授权处理。

  JWT的设计具有以下优势:

  1.   可以在不需要存储令牌的情况下实现无状态身份验证和授权。
  2.   适用于跨域场景,因为JWT可以作为HTTP头部或URL参数在客户端和服务器之间传递。
  3.   声明(claims)可以包含有关用户的任何有用信息,并且是可自定义的。
  4.   需要注意的是,JWT令牌是基于Base64编码的,但并不是加密的。因此,令牌的内容可以被解码和读取,但不能被修改,因为任何修改都会使签名无效。

  使用JWT时需要小心保护令牌的机密信息,避免将敏感信息直接存储在载荷中,最好将敏感信息放在服务器端进行处理。此外,对于令牌的过期时间也需要进行适当的管理和更新。

  5.2 jwt校验

  1.解析header, 确认alg。
  2.签名校验 - 根据传过来的header和payload按 alg指明的算法进行签名,将签名结果和传过来的sign进行对比,若对比一致,则校验通过。
  3.获取payload自定义内容。

6.实现

  6.1自定义实现token

  对token实现一个例子:

import hmac
import json
import time
import base64

header={'alg':'HS256','typ':'JWT'}
header_str=json.dumps(header)
h=base64.b64encode(header_str.encode())
print(h)

#2.payload
#设置有效期m秒,私有声明存放用户名user
payload={"exp":time.time()+5000,"username":"wangxi"}
payload_str=json.dumps(payload)
p=base64.b64encode(payload_str.encode())
print(p)
#3.sign:签名
sign=hmac.new(
    key=b"123456",
    msg=h+b'.'+p,
    digestmod="SHA256"
).hexdigest()
print("sign",sign)
s=base64.b64encode(sign.encode())
print(s)
token=h+ b"." + p + b"." + s  #注意,拼接起来的每一个都是字节串类型
print("token",token)#b'eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJleHAiOiAxNjkwOTY1NjM1LjI3NzIyNTUsICJ1c2VybmFtZSI6ICJ3YW5neGkifQ==.NWE4MWYxNTg3OThmZTQ5NTM1YWM5YWU0YTc4ZGEzZjk4MTE4ZTViNWVhMjNlMTNkNmFlMzM4MzYwNjMxMjRlMw=='

  下面是封装并检查token合法性代码

"""
jwt模块
"""
import base64
import hmac
import json
import time

class Jwt:
    def __init__(self):
        pass

    def make_token(self,payload,key):
        header={"alg":"HS256","typ":"JWT"}
        header_str = json.dumps(header)
        h_base64 = base64.b64encode(header_str.encode())
        #payload = {"exp": time.time() + 5000, "username": "wangxi"}
        payload_str = json.dumps(payload)
        p_base64 = base64.b64encode(payload_str.encode())

        sign = hmac.new(
            key=key.encode(),
            msg=h_base64 + b'.' + p_base64,
            digestmod="SHA256"
        ).hexdigest()
        s_base64 = base64.b64encode(sign.encode())
        token = h_base64 + b"." + p_base64 + b"." + s_base64
        return token


    def check_token(self,token,key):
        """
        :param token:
        :return:
        """
        h, p, s = token.split(b'.')
        sign_server = hmac.new(
            key=b'123456',
            msg=h + b'.' + p,
            digestmod="SHA256"
        ).hexdigest()  # string
        sign_server = base64.b64encode(sign_server.encode())
        if sign_server != s:
            raise Exception("token不合法")
        else:
            p_str = base64.b64decode(p)
            json_str = p_str.decode()
            p_dic = json.loads(json_str)
            exp = p_dic.get("exp")
            now = time.time()
            if now > exp:
                raise Exception("token过期了")
            else:
                print("没有过期")
        return p

if __name__ == '__main__':
    jwt=Jwt()
    payload={
        "exp":time.time()+5,
        "username":"wanxi"
    }
    key="123456"
    token=jwt.make_token(payload=payload,key=key)
    print(token)
    print(len(token))
    time.sleep(5)
    try:
        payload=jwt.check_token(token,key)
        print(payload)
        #
    except  Exception as e:
        print(e)

  6.2 pyjwt库实现token

  安装pyjwt:  pip install pyjwt -i  https://pypi.tuna.tsinghua.edu.cn/simple/

import time
import jwt
#1.生成token:jwt.encode(pay,key,algorithms)
payload={
    "exp":time.time()+5,
    "username":"wangxi",
         }
key="123456"
token=jwt.encode(payload,key)# 默认hs256 ,algorithm: str | None = "HS256",
print(token)
#2.校验token
time.sleep(6)#休眠6秒后,token失效,会报错
payload=jwt.decode(token,key,algorithms="HS256")
print(payload)

  对于pyjwt库实现生成的token,最后面永远没有==号。是为了优化处理,节省空间。检查token时可能采取了加上==的方法。

  前面代码中是这样的:print("token",token)#b'前面部分省略hmZTQ5NTM1M4MzYwNjMxMjRlMw=='。

小结:base64所有方法的参数和结果都是字节串,如果是在url中使用base64时,应该用urlsafe_b64encode与urlsafe_b64decode。http协议是不保存浏览器客户端状态的,是一种无状态连接协议。所以当我们关闭页面,在输入地址打开该页面有时候也能还原上次的页面状态,就用到了session,注意session是存储到服务器端运行内存中的,重启服务器session将丢失。不只是session,而且cookie也有失效时间,可以设置。针对cookie最多只能存储4kb数据,html5提供了一种新技术localStorage,一般支持5M的大小。另外,本文没有对cookie作过多的说明,等后期加上。如果客户端禁止了cookie的话,每次会话,session都会新创建。token相对session而言,简洁,不用对session数据进行清除管理等操作,而且当cookie被截获,其session将可能被跨站请求伪造攻击。关于加密算法,本文没有过多讨论,重在token的组成与实现。这里再补充下,我们使用labelme标注得到的json文件中,imageData的值也是base64编码。

  若存在不足或错误之处欢迎指正与评论!

 

参考资料:

https://blog.csdn.net/m0_53856016/article/details/126858443

https://blog.csdn.net/m0_61355190/article/details/126000130

posted @ 2023-08-05 23:01  wancy  阅读(39)  评论(0编辑  收藏  举报