一般概念 — ItsDangerous 文档
一般概念
序列化程序与签名者
它的危险提供了两个级别的数据处理。 签名接口是基于给定签名参数对给定bytes
值进行签名的基本系统。 序列化接口包装了一个签名者,以启用除bytes
之外的其他数据的序列化和签名。
通常,您需要使用序列化程序,而不是签名者。 您可以通过序列化程序配置签名参数,甚至可以提供回退签名者以将旧令牌升级为新参数。
秘钥
签名由 secret_key
保护。 通常,所有签名者都使用一个密钥,盐用于区分不同的上下文。 更改密钥将使现有令牌无效。
它应该是一长串随机字节。 此值必须保密,不应保存在源代码中或提交给版本控制。 如果攻击者获悉密钥,他们可以更改和放弃数据以使其看起来有效。 如果您怀疑发生了这种情况,请更改密钥以使现有令牌无效。
将密钥分开的一种方法是从环境变量中读取它。 首次部署时,在运行应用程序时生成密钥并设置环境变量。 所有进程管理器(如 systemd)和托管服务都有指定环境变量的方法。
import os
from itsdangerous.serializer import Serializer
SECRET_KEY = os.environ.get("SECRET_KEY")
s = Serializer(SECRET_KEY)
$ export SECRET_KEY="base64 encoded random bytes"
$ python application.py
生成密钥的一种方法是使用 os.urandom()
。
$ python3 -c 'import os; print(os.urandom(16).hex())'
盐
盐与秘钥相结合,推导出唯一的密钥,用于区分不同的上下文。 与密钥不同,盐不必是随机的,可以保存在代码中。 它只需要在上下文之间是唯一的,而不是私有的。
例如,您希望通过电子邮件发送激活链接以激活用户帐户,并通过升级链接将用户升级到付费帐户。 如果您签署的只是用户 ID,并且您不使用不同的盐,则用户可以重用激活链接中的令牌来升级帐户。 如果您使用不同的盐,签名将不同,并且在其他上下文中无效。
from itsdangerous.url_safe import URLSafeSerializer
s1 = URLSafeSerializer("secret-key", salt="activate")
s1.dumps(42)
'NDI.MHQqszw6Wc81wOBQszCrEE_RlzY'
s2 = URLSafeSerializer("secret-key", salt="upgrade")
s2.dumps(42)
'NDI.c0MpsD6gzpilOAeUPra3NShPXsE'
由于盐不同,第二个序列化程序无法加载与第一个序列化程序一起转储的数据。
s2.loads(s1.dumps(42))
Traceback (most recent call last):
...
BadSignature: Signature does not match
只有具有相同盐的序列化程序才能加载数据。
s2.loads(s2.dumps(42))
42
密钥轮换
密钥轮换可以为发现秘密密钥的攻击者提供额外的缓解措施。 轮换系统将保留有效密钥列表,生成新密钥并定期删除最旧的密钥。 如果攻击者破解密钥需要 4 周时间,但密钥在 3 周后轮换使用,他们将无法使用他们破解的任何密钥。 但是,如果用户在三周内没有刷新他们的令牌,它也将无效。
生成和维护此列表的系统不在 ItsDangerous 的范围内,但 ItsDangerous 确实支持针对密钥列表进行验证。
您可以传递一个键列表,从最旧到最新,而不是传递单个键。 签名时将使用最后一个(最新)密钥,并且在验证每个密钥时,将在引发验证错误之前从最新到最旧尝试。
SECRET_KEYS = ["2b9cd98e", "169d7886", "b6af09f5"]
# sign some data with the latest key
s = Serializer(SECRET_KEYS)
t = s.dumps({"id": 42})
# rotate a new key in and the oldest key out
SECRET_KEYS.append("cf9b3588")
del SECRET_KEYS[0]
s = Serializer(SECRET_KEYS)
s.loads(t) # valid even though it was signed with a previous key
摘要方法安全
签名者配置有 digest_method
,这是一个哈希函数,在生成 HMAC 签名时用作中间步骤。 默认方法是 hashlib.sha1()
。 有时,用户会担心这种默认设置,因为他们听说过与 SHA-1 的哈希冲突。
当用作 HMAC 中的中间迭代步骤时,SHA-1 不是不安全的。 事实上,即使是 MD5 在 HMAC 中仍然是安全的。 在 HMAC 中使用时,单独的散列安全性不适用。
如果一个项目无论如何都认为 SHA-1 是一种风险,他们可以使用不同的摘要方法配置签名者,例如 hashlib.sha512()
。 可以配置 SHA-1 的后备签名者,以便升级旧令牌。 SHA-512 生成更长的哈希值,因此令牌将占用更多空间,这与 cookie 和 URL 相关。