加密签名 — Django 6.0.4 documentation
创始人
2026-06-16 10:09:23

加密签名

Web 应用安全的黄金法则是永远不要信任来自不可信来源的数据。有时,通过不可信渠道传递数据可能会很有用。通过加密签名的值可以通过不可信渠道传递,因为我们可以安全地知道任何篡改都将被检测到。

Django 提供了用于签名值的低级 API 和用于设置和读取签名 cookie 的高级 API,签名在 web 应用程序中最常见的用途之一就是签名 cookie。

你可能还发现签名对以下方面很有用:

  • 生成“找回我的账户”URL 以发送给丢失密码的用户。

  • 确认存储在表单隐藏字段中的数据未被篡改。

  • 生成一次性的秘密 URL,允许临时访问受保护的资源,例如用户付费下载的文件。

保护 SECRET_KEY 和 SECRET_KEY_FALLBACKS

当你使用 startproject 创建一个新的Django项目时,settings.py 文件会自动生成,并随机得到一个 SECRET_KEY 值。这个值是保证签名数据安全的关键——你必须保证这个值的安全,否则攻击者可以用它来生成自己的签名值。

SECRET_KEY_FALLBACKS 可以用于轮换密钥。这些值不会用于签署数据,但如果指定了,它们将用于验证签署的数据,并必须保持安全。

使用低级 API

Django 的签名方法位于 django.core.signing 模块中。要签署一个值,首先实例化一个 Signer 实例:

>>> from django.core.signing import Signer
>>> signer = Signer()
>>> value = signer.sign("My string")
>>> value
'My string:v9G-nxfz3iQGTXrePqYPlGvH79WTcIgj1QIQSUODTW0'

签名被追加到字符串的末尾,跟在冒号后面。你可以使用 unsign 方法检索原始值:

>>> original = signer.unsign(value)
>>> original
'My string'

如果你将一个非字符串值传递给 sign,该值将在签名之前被强制转换为字符串,而 unsign 的结果将给你该字符串值:

>>> signed = signer.sign(2.5)
>>> original = signer.unsign(signed)
>>> original
'2.5'

如果你希望保护一个列表、元组或字典,可以使用 sign_object() 和 unsign_object() 方法来实现:

>>> signed_obj = signer.sign_object({"message": "Hello!"})
>>> signed_obj
'eyJtZXNzYWdlIjoiSGVsbG8hIn0:bzb48DBkB-bwLaCnUVB75r5VAPUEpzWJPrTb80JMIXM'
>>> obj = signer.unsign_object(signed_obj)
>>> obj
{'message': 'Hello!'}

详见 保护复杂的数据结构。

如果签名或值已经被以任何方式更改,将会引发 django.core.signing.BadSignature 异常:

>>> from django.core import signing
>>> value += "m"
>>> try:
...     original = signer.unsign(value)
... except signing.BadSignature:
...     print("Tampering detected!")
...

默认情况下,Signer 类使用 SECRET_KEY 设置来生成签名。你可以通过将不同的秘钥传递给 Signer 构造函数来使用不同的秘钥:

>>> signer = Signer(key="my-other-secret")
>>> value = signer.sign("My string")
>>> value
'My string:o3DrrsT6JRB73t-HDymfDNbTSxfMlom2d8TiUlb1hWY'
class Signer(*, key=None, sep=':', salt=None, algorithm=None, fallback_keys=None)[source]

Returns a signer which uses key to generate signatures and sep to separate values. sep cannot be in the URL safe base64 alphabet. This alphabet contains alphanumeric characters, hyphens, and underscores. algorithm must be an algorithm supported by hashlib, it defaults to 'sha256'. fallback_keys is a list of additional values used to validate signed data, defaults to SECRET_KEY_FALLBACKS.

使用 salt 参数

如果你不希望每次出现特定字符串时都具有相同的签名哈希值,可以使用 Signer 类的可选参数 salt。使用盐会为签名哈希函数提供盐和你的 SECRET_KEY:

>>> signer = Signer()
>>> signer.sign("My string")
'My string:v9G-nxfz3iQGTXrePqYPlGvH79WTcIgj1QIQSUODTW0'
>>> signer.sign_object({"message": "Hello!"})
'eyJtZXNzYWdlIjoiSGVsbG8hIn0:bzb48DBkB-bwLaCnUVB75r5VAPUEpzWJPrTb80JMIXM'
>>> signer = Signer(salt="extra")
>>> signer.sign("My string")
'My string:YMD-FR6rof3heDkFRffdmG4pXbAZSOtb-aQxg3vmmfc'
>>> signer.unsign("My string:YMD-FR6rof3heDkFRffdmG4pXbAZSOtb-aQxg3vmmfc")
'My string'
>>> signer.sign_object({"message": "Hello!"})
'eyJtZXNzYWdlIjoiSGVsbG8hIn0:-UWSLCE-oUAHzhkHviYz3SOZYBjFKllEOyVZNuUtM-I'
>>> signer.unsign_object(
...     "eyJtZXNzYWdlIjoiSGVsbG8hIn0:-UWSLCE-oUAHzhkHviYz3SOZYBjFKllEOyVZNuUtM-I"
... )
{'message': 'Hello!'}

Using salt in this way puts the different signatures into different namespaces. A signature that comes from one namespace (a particular salt value) cannot be used to validate the same plaintext string in a different namespace that is using a different salt setting. The result is to prevent an attacker from using a signed string generated in one place in the code as input to another piece of code that is generating (and verifying) signatures using a different salt.

与你的 SECRET_KEY 不同,你的盐参数不需要保密。

验证时间戳值

TimestampSigner 是 Signer 的子类,它会在值后附加一个带签名的时间戳。这允许你确认一个签名值是否在指定的时间段内创建:

>>> from datetime import timedelta
>>> from django.core.signing import TimestampSigner
>>> signer = TimestampSigner()
>>> value = signer.sign("hello")
>>> value
'hello:1stLqR:_rvr4oXCgT4HyfwjXaU39QvTnuNuUthFRCzNOy4Hqt0'
>>> signer.unsign(value)
'hello'
>>> signer.unsign(value, max_age=10)
SignatureExpired: Signature age 15.5289158821 > 10 seconds
>>> signer.unsign(value, max_age=20)
'hello'
>>> signer.unsign(value, max_age=timedelta(seconds=20))
'hello'
class TimestampSigner(*, key=None, sep=':', salt=None, algorithm='sha256')[source]
sign(value)[source]

签名 value 并附加当前时间戳。

unsign(value, max_age=None)[source]

Checks if value was signed less than max_age seconds ago, otherwise raises SignatureExpired. The max_age parameter can accept an integer or a datetime.timedelta object.

sign_object(obj, serializer=JSONSerializer, compress=False)

对复杂的数据结构(例如列表、元组或字典)进行编码,可选地压缩数据,追加当前时间戳,并对其进行签名。

unsign_object(signed_obj, serializer=JSONSerializer, max_age=None)

Checks if signed_obj was signed less than max_age seconds ago, otherwise raises SignatureExpired. The max_age parameter can accept an integer or a datetime.timedelta object.

保护复杂的数据结构

如果你希望保护一个列表、元组或字典,可以使用 Signer.sign_object() 和 unsign_object() 方法,或者使用签名模块的 dumps() 或 loads() 函数(它们是 TimestampSigner(salt='django.core.signing').sign_object()/unsign_object() 的快捷方式)。这些方法在底层使用了 JSON 序列化。JSON 确保即使你的 SECRET_KEY 被窃取,攻击者也无法通过利用 pickle 格式来执行任意命令:

>>> from django.core import signing
>>> signer = signing.TimestampSigner()
>>> value = signer.sign_object({"foo": "bar"})
>>> value
'eyJmb28iOiJiYXIifQ:1stLrZ:_QiOBHafwucBF9FyAr54qEs84ZO1UdsO1XiTJCvvdno'
>>> signer.unsign_object(value)
{'foo': 'bar'}
>>> value = signing.dumps({"foo": "bar"})
>>> value
'eyJmb28iOiJiYXIifQ:1stLsC:JItq2ZVjmAK6ivrWI-v1Gk1QVf2hOF52oaEqhZHca7I'
>>> signing.loads(value)
{'foo': 'bar'}

由于 JSON 的性质(没有本地区分列表和元组的方式),如果你传递一个元组,你将从 signing.loads(object) 得到一个列表:

>>> from django.core import signing
>>> value = signing.dumps(("a", "b", "c"))
>>> signing.loads(value)
['a', 'b', 'c']
dumps(obj, key=None, salt='django.core.signing', serializer=JSONSerializer, compress=False)[source]

返回 URL 安全的,经过签名的 base64 压缩 JSON 字符串。使用 TimestampSigner 对序列化对象进行签名。

loads(string, key=None, salt='django.core.signing', serializer=JSONSerializer, max_age=None, fallback_keys=None)[source]

与 dumps() 相反,如果签名失败引发 BadSignature。如果给定,则检查 max_age (以秒为单位)。

⚠️
本网站信息内容及素材来源于网络采集或用户发布,如涉及侵权,请及时联系我们,发送链接至2697952338@QQ.COM,我们将第一时间进行核实与删除处理。

相关内容

热门资讯

智易购APP无资质经营贵金属期...   智易购APP如今受害者众多,投资人在该平台做交易,只要是大资金买入,基本都是反向走势,一买涨,就...
斑马投资APP虚假商品订购交易...   网上宣传的斑马投资APP交易平台真实靠谱吗?在这个平台做交易出现严重亏损,平台莫名其妙的卡顿和跟...
吉鑫乐享APP夸大宣传诱导充值...   网上众多的白银交易软件,大部分背后是长沙白安安网络科技有限公司,看似正规的平台,其实就是在给投资...
易掘金APP无资质冒充商城订购...   易掘金APP大肆鼓吹其商品订购业务“收益可观、操作灵活”,吸引大量普通民众投入资金,不少人甚至将...
充钱就能赚?大吉订购APP&q...   大吉订购APP是骗局吗?投资者在大吉订购软件上做贵金属交易亏钱了,这是正常的亏损?大吉订购这个交...
铂银壹号APP贵金属投资骗局,...   中小投资者在网上参与商品现货订购交易,表面看似合规合法,实则暗藏难以察觉的风险。商品现货交易本应...
兴鑫淘金APP无牌照运营投资骗...   兴鑫淘金APP投资人亏损的资金能追回?该平台是否有期货经营资质?为什么一个现货订购平台能做高杠杆...
警惕!铂银掘金APP被指收割投...   投资者警惕!“铂银掘金APP”被指收割投资者,高额手续费与后台操控成亏损元凶  近期,甘肃西北商...
八方淘金APP商品订购涉嫌非法...   八方淘金APP(甘肃西北商品交易市场有限公司)投资亏损如何挽回?该平台是否具备合法资质?众多投资...
5元起投实现财富自由?指尖订购...   贵州云上大宗商品交易有限公司(贵州云上大宗现货商品交易中心有限公司)并非期货交易平台,旗下金鳞订...