本文是在阅读了下面2篇作品后进行的总结
https://xz.aliyun.com/news/3201
https://www.leavesongs.com/PENETRATION/client-session-security.html
1. 什么是 Flask Session
Flask 是一个轻量级 Python Web 框架。它没有自带数据库操作,所以 session(用户会话信息)默认存储在客户端 cookie 中。
session 是用来认证用户身份的,例如判断用户是否登录,是否是管理员等。
客户端 session vs 服务端 session
-
服务端 session(如 PHP 默认)
-
session 数据保存在服务器。
-
cookie 中只存储 session id。
-
用户无法直接看到数据内容。
-
-
客户端 session(Flask 默认)
-
session 数据直接存储在客户端 cookie 中。
-
cookie 里的数据是明文可读,通过 HMAC 签名保证不可被篡改。
-
如果 SECRET_KEY 泄露,攻击者可以伪造任意 session。
-
2. Flask session 的生成机制
Flask 使用 SecureCookieSessionInterface 处理 session,其核心逻辑:
2.1 代码流程
val = self.get_signing_serializer(app).dumps(dict(session))
response.set_cookie(app.session_cookie_name, val,
expires=expires, httponly=httponly,
domain=domain, path=path, secure=secure)
解释:
-
dict(session):把 session 数据(Python 字典)转换成 dict。 -
dumps():-
将 dict 序列化成 JSON 字符串。
-
压缩(zlib)如果压缩后更短。
-
Base64 编码。
-
用 HMAC + SECRET_KEY 签名。
-
-
set_cookie():把签名后的 session 写入客户端 cookie。
2.2 URLSafeTimedSerializer 主要方法
class URLSafeTimedSerializer(URLSafeSerializerMixin, TimedSerializer):
default_serializer = compact_json
-
dump_payload():序列化 session 数据 → JSON → 压缩 → base64 编码。 -
dumps():在dump_payload()基础上计算 HMAC 签名。 -
签名只防篡改,不能防止被读取。
Flask Session 生成机制总结
session 是一个 Python 字典-序列化-压缩(可选)-Base64 编码-签名
3. Flask session 解密示例
假设有一个 session cookie:
eyJ1c2VyX2lkIjo2fQ.XA3a4A.R-ReVnWT8pkpFqM_52MabkZYIkY
3.1 简单解码方法
from itsdangerous import base64_decode
s = "eyJ1c2VyX2lkIjo2fQ.XA3a4A.R-ReVnWT8pkpFqM_52MabkZYIkY"
data, timestamp, signature = s.split('.')
payload = base64_decode(data)
print(payload) # 输出:b'{"user_id":6}'
解释:
-
data部分是 payload,base64 解码后得到 JSON 字符串。 -
timestamp部分是生成时间,base64 解码后可转为整数。 -
signature是 HMAC 签名,保证 payload 未被篡改。
3.2 P 师傅提供的脚本(支持压缩)
#!/usr/bin/env python3
import sys, zlib
from base64 import b64decode
from flask.sessions import session_json_serializer
from itsdangerous import base64_decode
def decryption(payload):
payload, sig = payload.rsplit(b'.', 1)
payload, timestamp = payload.rsplit(b'.', 1)
decompress = False
if payload.startswith(b'.'):
payload = payload[1:]
decompress = True
payload = base64_decode(payload)
if decompress:
payload = zlib.decompress(payload)
return session_json_serializer.loads(payload)
if __name__ == '__main__':
print(decryption(sys.argv[1].encode()))
说明:
sys:用来获取命令行参数(cookie 字符串)。
zlib:解压缩模块,Flask 在 session 压缩后才存储。
b64decode:Base64 解码,把 ASCII 字符串还原成二进制。
session_json_serializer:Flask 内部的 JSON 序列化器,把解码后的二进制还原成 Python 对象。
base64_decode(来自 itsdangerous):Flask 用它做 Base64 解码,兼容 URL 安全编码。
def decryption(payload):
payload 是你传入的 Flask cookie(session 字符串),格式一般是:
eyJ1c2VyX2lkIjoxLCJpc19hZG1pbiI6ZmFsc2V9.XYZ123.abc456
三部分用 . 分隔:payload:序列化后的 session 数据
timestamp:时间戳
sig:签名(HMAC,用于防篡改)
payload, sig = payload.rsplit(b'.', 1)
payload, timestamp = payload.rsplit(b'.', 1)
rsplit(b'.', 1):从右边拆分,拆一次得到最后的签名。第二次拆分得到时间戳和真正的 payload 数据。
举例:
cookie = b'eyJ1c2VyX2lkIjox.XA3a4A.R-ReVnWT8pkFqM_52MabkZYIkY'
payload, sig = cookie.rsplit(b'.', 1)
# payload = b'eyJ1c2VyX2lkIjox.XA3a4A', sig = b'R-ReVnWT8pkFqM_52MabkZYIkY'
payload, timestamp = payload.rsplit(b'.', 1)
# payload = b'eyJ1c2VyX2lkIjox', timestamp = b'XA3a4A'
decompress = False
if payload.startswith(b'.'):
payload = payload[1:]
decompress = True
Flask 有时会 压缩 session 数据(zlib),压缩后的 payload 开头会加一个 .。如果发现开头是 .,就去掉,并标记需要解压。
payload = base64_decode(payload)
Flask 把 session 数据做了 Base64 编码,方便存储在 cookie 中。这里先把 Base64 转回二进制数据。
if decompress:
payload = zlib.decompress(payload)
如果标记了压缩,就用 zlib.decompress() 解压。解压后的 payload 就是原始 JSON 字符串。
return session_json_serializer.loads(payload)
session_json_serializer 是 Flask 内置的 JSON 解析器。它把 JSON 字符串转换成 Python 对象(通常是字典)。
举例:
payload = b'{"user_id":1,"is_admin":false}'
session_json_serializer.loads(payload)
# 输出
{'user_id': 1, 'is_admin': False}
4. 客户端 session 安全问题
4.1 敏感信息泄露
案例:
session['token'] = "d41d8cd98f00b204e9800998ecf8427e"
-
token 用于邮箱找回密码认证。
-
因为 Flask session 存在客户端,攻击者可以:
-
解密 cookie
-
获取 token
-
直接修改密码
-
4.2 验证码绕过
Flask 验证码示例:
captcha_code = ''.join(sample_chars())
session['captcha'] = captcha_code
-
访问
/captcha时生成图片。 -
session 中保存了验证码。
-
解密 cookie 即可直接获取验证码,绕过验证。
4.3 Session 伪造
攻击链:
-
读取 session 内容:如
{"user_id":1,"is_admin":false}。 -
获取 SECRET_KEY:通过泄露或弱随机 key。
-
伪造 session:
{"user_id":1,"is_admin":true},用其生成新的 cookie。 -
访问高权限接口:绕过权限验证。
示例伪造:
from itsdangerous import URLSafeTimedSerializer
from flask.sessions import session_json_serializer
secret_key = "KNOWN_SECRET_KEY"
s = URLSafeTimedSerializer(secret_key, salt='cookie-session', serializer=session_json_serializer)
cookie_value = s.dumps({"user_id":1, "is_admin": True})
print(cookie_value)
5. 类似框架问题
CodeIgniter 2.x
-
session 存储在 cookie 中,默认用 PHP
serialize()+ 签名。 -
可选加密,但存在弱加密或 Mcrypt 未安装时的漏洞。
-
可通过简单脚本破解密钥,伪造任意 session。
6. 防护建议
-
不要在客户端 session 中存储敏感信息
-
不要存储权限标志或 token。
-
-
使用强随机 SECRET_KEY
import secrets app.secret_key = secrets.token_urlsafe(32) -
优先使用服务端 session
-
Flask-Session 支持 Redis、数据库、Memcached 存储。
-
Cookie 仅保存 session_id。
-
-
安全 cookie 设置
app.config.update( SESSION_COOKIE_HTTPONLY=True, SESSION_COOKIE_SECURE=True, SESSION_COOKIE_SAMESITE='Lax' ) -
管理 session 生命周期
-
设置 PERMANENT_SESSION_LIFETIME。
-
关键操作后刷新或失效 session。
-
-
审计与监控
-
检测异常 session 行为(频繁 IP 切换)。
-
记录重要操作日志。
-
Flask Session机制与安全防护
1万+

被折叠的 条评论
为什么被折叠?



