bigywater.tech
Flask · 119

SECRET_KEY 的用途

SECRET_KEY 到底保护什么?cookie 里的内容能被用户看到吗?key 泄漏后果多严重?怎么轮换而不让所有人下线?这篇用真实的伪造、轮换和猜测把每个问题验证一遍。

明文可读
session cookie 的载荷不需要密钥就能解出
admin
用泄漏的 key 伪造的 session 被服务端接受的角色
0.1 ms
弱 key "dev" 被词表猜中的用时

没有 SECRET_KEY

实测 · 本机执行输出
  HTTP 500
  (传播出来的异常) RuntimeError: The session is unavailable because no secret key was set.  Set the secret_key on the application to 

上一篇:Streaming JSON;下一篇:Session Cookie 安全属性。

cookie 的内容

实测 · 本机执行输出
  cookie: eyJyb2xlIjoidXNlciIsInVzZXIiOiJhbm4ifQ.ar9AiQ.hP1CkQxFNkgTMgvoqMb20U_P…
  不用密钥解出的内容: {"role":"user","user":"ann"}
  cookie 的三段: [38, 6, 27] (载荷.时间戳.签名)

key 泄漏

实测 · 本机执行输出
  用正确的 key 伪造的 cookie → {'role': 'admin', 'user': 'mallory'}
  用错误的 key 伪造的 cookie → {'role': None, 'user': None} (签名不对,当作没有 session)
  篡改签名的 cookie → {'role': None, 'user': None}

换 key

实测 · 本机执行输出
  换 key 之前: {'role': 'user', 'user': 'ann'}
  换 key 之后(同一个 cookie): {'role': None, 'user': None}

平滑轮换

实测 · 本机执行输出
  新 key + FALLBACKS=[旧 key],带旧 cookie → {'role': 'user', 'user': 'ann'}
  之后服务端下发的 cookie 已经用新 key 签名: 旧 cookie 能被旧 key 验证: True | 新下发的 cookie 能被新 key 验证: True | 能被旧 key 验证: False
  只有新 key、没有 FALLBACKS,带旧 cookie → {'role': None, 'user': None}

弱 key

实测 · 本机执行输出
  字典猜测:猜中 'dev',用时 0.1 ms
  强 key(64 个十六进制字符):试了 200010 个候选,结果 None,用时 2462 ms(约 12.3 µs/个)
  随机 32 字节 key 有 2^256 种可能;按每秒试 81243 个算,穷举不可行(这里没有真的穷举)
  生成方式:secrets.token_hex(32) → 74b2d59ed6e401c9… (64 个字符)

只对自己生成的 cookie 做猜测,没有对任何别人的系统做过测试。

分步演示

SECRET_KEY 的用途
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Python 3.14.7 / Flask 3.1.3 / Werkzeug 3.1.9 / Jinja2 3.1.6 / SQLAlchemy 2.1.1 / gunicorn 26.2.0(都装在自己的虚拟环境里);大多数实验用 Flask 的 test_client(直接调用 WSGI 应用,不经过网络),需要真实 HTTP 时另起 gunicorn 或开发服务器(端口 9600 以上,本机 127.0.0.1);计时用 time.perf_counter,数字每次运行会有小幅抖动。itsdangerous(Flask 的 session 序列化器)
    • 没有验证:真实攻击工具的猜测速度(我的 Python 实现每秒约 8 万个,专业工具远快于此)、其它用到 SECRET_KEY 的扩展(Flask-WTF 的 CSRF token、Flask-Login 的 remember cookie)在轮换时的行为、把 key 存在环境变量或密钥管理服务里的做法
    京ICP备2026067502号-1京公网安备11010502063487号