Skip to main content

Detect tampered signed values

When you transmit data to a client and expect to receive it back unchanged, you need a way to verify that the data was not tampered with during its time outside your control. If a user modifies a signed value—for example, by changing a user ID or a permission level in a cookie—the verification process must detect this change and reject the data.

The itsdangerous.Signer class provides this integrity check by appending a cryptographic signature to your data. When you attempt to retrieve the original value, the library recalculates the signature and compares it to the one provided. If they do not match, it raises an itsdangerous.BadSignature exception.

from itsdangerous import BadSignature, Signer

signer = Signer(b"secret-key")
original = b"hello"
signed = signer.sign(original)

# First unsign: verify the valid signed value
assert signer.unsign(signed) == original

# Tamper with the signed value by changing the last byte
tampered = signed[:-1] + b"!"

# Second unsign: prove that tampering raises BadSignature
try:
signer.unsign(tampered)
except BadSignature as e:
assert e.payload is not None

How Signer works internally

The itsdangerous.Signer class uses the HMAC algorithm (defaulting to SHA-1 via itsdangerous.signer.HMACAlgorithm) to generate a signature. When you call signer.sign(value), the following steps occur:

  1. The Signer generates a signature for the input bytes using the secret_key and an optional salt.
  2. The signature is encoded using URL-safe base64.
  3. The original value and the signature are joined using a separator (defaulting to .).

When signer.unsign(signed_value) is called, the itsdangerous.signer.Signer.get_signature method is used to re-derive the expected signature from the payload portion of the input. The library then uses hmac.compare_digest to perform a constant-time comparison between the provided signature and the expected one, protecting against timing attacks.

Handling BadSignature

The itsdangerous.BadSignature exception is the primary signal that data integrity has been compromised. It is defined in itsdangerous.exc and inherits from BadData.

A key feature of BadSignature is that it preserves the payload that failed the check. While you should generally treat tampered data as untrusted and discard it, the payload attribute allows you to inspect what the modified data looked like for logging or debugging purposes. This is particularly useful when the signature is valid but the format of the data itself is corrupted, or when you need to track specific tampering patterns.