Serialization Interface¶
The Signing Interface only signs strings. To sign other types, the
Serializer
class provides a dumps
/loads
interface
similar to Python’s json
module, which serializes the object to a
string then signs that.
Use dumps()
to serialize and sign the data:
from itsdangerous.serializer import Serializer
s = Serializer("secret-key")
s.dumps([1, 2, 3, 4])
b'[1, 2, 3, 4].r7R9RhGgDPvvWl3iNzLuIIfELmo'
Use loads()
to verify the signature and deserialize
the data.
s.loads('[1, 2, 3, 4].r7R9RhGgDPvvWl3iNzLuIIfELmo')
[1, 2, 3, 4]
By default, data is serialized to JSON. If simplejson is installed, it
is preferred over the built-in json
module. This internal
serializer can be changed by subclassing.
To record and validate the age of the signature, see Signing With Timestamps. To serialize to a format that is safe to use in URLs, see URL Safe Serialization.
The Salt¶
All classes also accept a salt argument. The name might be misleading because usually if you think of salts in cryptography you would expect the salt to be something that is stored alongside the resulting signed string as a way to prevent rainbow table lookups. Such salts are usually public.
In itsdangerous, like in the original Django implementation, the salt serves a different purpose. You could describe it as namespacing. It’s still not critical if you disclose it because without the secret key it does not help an attacker.
Let’s assume that you have two links you want to sign. You have the activation link on your system which can activate a user account and you have an upgrade link that can upgrade a user’s account to a paid account which you send out via email. If in both cases all you sign is the user ID a user could reuse the variable part in the URL from the activation link to upgrade the account. Now you could either put more information in there which you sign (like the intention: upgrade or activate), but you could also use different salts:
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'
The second serializer can’t load data dumped with the first because the salts differ:
s2.loads(s1.dumps(42))
Traceback (most recent call last):
...
itsdangerous.exc.BadSignature: Signature "MHQqszw6Wc81wOBQszCrEE_RlzY" does not match
Only the serializer with the same salt can load the data:
s2.loads(s2.dumps(42))
42
Responding to Failure¶
Exceptions have helpful attributes which allow you to inspect the payload if the signature check failed. This has to be done with extra care because at that point you know that someone tampered with your data but it might be useful for debugging purposes.
from itsdangerous.serializer import Serializer
from itsdangerous.exc import BadSignature, BadData
s = URLSafeSerializer("secret-key")
decoded_payload = None
try:
decoded_payload = s.loads(data)
# This payload is decoded and safe
except BadSignature as e:
if e.payload is not None:
try:
decoded_payload = s.load_payload(e.payload)
except BadData:
pass
# This payload is decoded but unsafe because someone
# tampered with the signature. The decode (load_payload)
# step is explicit because it might be unsafe to unserialize
# the payload (think pickle instead of json!)
If you don’t want to inspect attributes to figure out what exactly went
wrong you can also use loads_unsafe()
:
sig_okay, payload = s.loads_unsafe(data)
The first item in the returned tuple is a boolean that indicates if the signature was correct.
API¶
-
class
itsdangerous.serializer.
Serializer
(secret_key, salt=b'itsdangerous', serializer=None, serializer_kwargs=None, signer=None, signer_kwargs=None, fallback_signers=None)¶ This class provides a serialization interface on top of the signer. It provides a similar API to json/pickle and other modules but is structured differently internally. If you want to change the underlying implementation for parsing and loading you have to override the
load_payload()
anddump_payload()
functions.This implementation uses simplejson if available for dumping and loading and will fall back to the standard library’s json module if it’s not available.
You do not need to subclass this class in order to switch out or customize the
Signer
. You can instead pass a different class to the constructor as well as keyword arguments as a dict that should be forwarded.s = Serializer(signer_kwargs={'key_derivation': 'hmac'})
You may want to upgrade the signing parameters without invalidating existing signatures that are in use. Fallback signatures can be given that will be tried if unsigning with the current signer fails.
Fallback signers can be defined by providing a list of
fallback_signers
. Each item can be one of the following: a signer class (which is instantiated withsigner_kwargs
,salt
, andsecret_key
), a tuple(signer_class, signer_kwargs)
, or a dict ofsigner_kwargs
.For example, this is a serializer that signs using SHA-512, but will unsign using either SHA-512 or SHA1:
s = Serializer( signer_kwargs={"digest_method": hashlib.sha512}, fallback_signers=[{"digest_method": hashlib.sha1}] )
Changed in version 0.14:: The
signer
andsigner_kwargs
parameters were added to the constructor.Changed in version 1.1.0:: Added support for
fallback_signers
and configured a default SHA-512 fallback. This fallback is for users who used the yanked 1.0.0 release which defaulted to SHA-512.-
default_fallback_signers
= [{'digest_method': <built-in function openssl_sha512>}]¶ The default fallback signers.
-
default_serializer
= <module 'json' from '/home/user/.pyenv/versions/3.8.18/lib/python3.8/json/__init__.py'>¶ If a serializer module or class is not passed to the constructor this one is picked up. This currently defaults to
json
.
-
default_signer
¶ alias of
itsdangerous.signer.Signer
-
dump
(obj, f, salt=None)¶ Like
dumps()
but dumps into a file. The file handle has to be compatible with what the internal serializer expects.
-
dump_payload
(obj)¶ Dumps the encoded object. The return value is always bytes. If the internal serializer returns text, the value will be encoded as UTF-8.
-
dumps
(obj, salt=None)¶ Returns a signed string serialized with the internal serializer. The return value can be either a byte or unicode string depending on the format of the internal serializer.
-
iter_unsigners
(salt=None)¶ Iterates over all signers to be tried for unsigning. Starts with the configured signer, then constructs each signer specified in
fallback_signers
.
-
load_payload
(payload, serializer=None)¶ Loads the encoded object. This function raises
BadPayload
if the payload is not valid. Theserializer
parameter can be used to override the serializer stored on the class. The encodedpayload
should always be bytes.
-
load_unsafe
(f, *args, **kwargs)¶ Like
loads_unsafe()
but loads from a file.New in version 0.15.
-
loads
(s, salt=None)¶ Reverse of
dumps()
. RaisesBadSignature
if the signature validation fails.
-
loads_unsafe
(s, salt=None)¶ Like
loads()
but without verifying the signature. This is potentially very dangerous to use depending on how your serializer works. The return value is(signature_valid, payload)
instead of just the payload. The first item will be a boolean that indicates if the signature is valid. This function never fails.Use it for debugging only and if you know that your serializer module is not exploitable (for example, do not use it with a pickle serializer).
New in version 0.15.
-