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.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是一种用于跟踪用户会话的机制,以实现用户在不同请求之间的状态保持和数据共享。它通过在服务器端存储和管理用户相关数据,并通过一个唯一的标识符将会话与用户关联起来。工作原理如下:
- 用户在浏览器中发送一个HTTP请求到服务器,并携带一个唯一的标识符,通常称为Session ID。
- 服务器接收到请求后,根据Session ID查找关联的Session数据。如果找到了,则表示该用户存在会话,可以获取和修改Session中的数据。如果没有找到,则表示该用户是新用户,需要创建一个新的Session,并生成一个唯一的Session ID,同时会创建一个特殊的cookie。
- 服务器将Session ID作为Cookie的一部分发送给浏览器。浏览器在后续的请求中会自动将这个Cookie携带上来。
- 用户的后续请求在Cookie中携带了Session ID后,服务器会根据Session ID和服务器内存中存放的Session ID进行比对,获取关联的Session数据,并对其进行操作。
- 当用户会话结束(如关闭浏览器或超过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)
JWT(JSON 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的设计具有以下优势:
- 可以在不需要存储令牌的情况下实现无状态身份验证和授权。
- 适用于跨域场景,因为JWT可以作为HTTP头部或URL参数在客户端和服务器之间传递。
- 声明(claims)可以包含有关用户的任何有用信息,并且是可自定义的。
- 需要注意的是,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