La regla dorada de la seguridad en aplicaciones web es nunca confiar datos de fuentes no confiables. A veces puede ser útil pasar datos a través de un medio no confiable. Los valores firmados criptográficamente pueden pasar a través de un canal no confiable con la certeza de que cualquier manipulación se detectará.
Django proporciona tanto una API baja nivel para firmar valores como una API alta nivel para establecer y leer cookies firmadas, uno de los usos más comunes de la firma en aplicaciones web.
También puede encontrar útil la firma para lo siguiente:
Generando URLs para recuperar la cuenta de los usuarios que han perdido su contraseña.
Verificando si los datos almacenados en campos formularios ocultos no han sido manipulados.
Generando URLs secretas temporales para permitir el acceso temporal a un recurso protegido, por ejemplo, un archivo descargable que un usuario ha pagado.
SECRET_KEY y SECRET_KEY_FALLBACKS¶Cuando creas un nuevo proyecto Django utilizando startproject, se genera automáticamente el archivo settings.py y obtiene un valor aleatorio de la clave secreta SECRET_KEY. Este valor es la clave para asegurar los datos firmados – es vital que lo mantengas seguro, o los atacantes podrían utilizarlo para generar sus propios valores firmados.
Puedes utilizar SECRET_KEY_FALLBACKS para rotar claves secretas. Los valores no se utilizarán para firmar datos, pero si se especifican, se utilizarán para validar datos firmados y deben mantenerse seguros.
Los métodos de firma de Django viven en el módulo django.core.signing. Para firmar un valor, primero debes instanciar una instancia de Signer:
>>> from django.core.signing import Signer
>>> signer = Signer()
>>> value = signer.sign("My string")
>>> value
'My string:v9G-nxfz3iQGTXrePqYPlGvH79WTcIgj1QIQSUODTW0'
La firma se agrega al final de la cadena, después del dos puntos. Puedes recuperar el valor original utilizando el método unsign:
>>> original = signer.unsign(value)
>>> original
'My string'
Si pasas un valor no-cadena a sign, el valor se forzará a cadena antes de ser firmado, y el resultado de unsign te dará ese valor de cadena:
>>> signed = signer.sign(2.5)
>>> original = signer.unsign(signed)
>>> original
'2.5'
Si deseas proteger una lista, tupla o diccionario puedes hacerlo utilizando los métodos sign_object() y unsign_object():
>>> signed_obj = signer.sign_object({"message": "Hello!"})
>>> signed_obj
'eyJtZXNzYWdlIjoiSGVsbG8hIn0:bzb48DBkB-bwLaCnUVB75r5VAPUEpzWJPrTb80JMIXM'
>>> obj = signer.unsign_object(signed_obj)
>>> obj
{'message': 'Hello!'}
Consulte Protegiendo estructuras de datos complejas para obtener más detalles.
Si la firma o el valor han sido alterados de alguna manera, se levantará una excepción django.core.signing.BadSignature:
>>> from django.core import signing
>>> value += "m"
>>> try:
... original = signer.unsign(value)
... except signing.BadSignature:
... print("Tampering detected!")
...
Por defecto, la clase Signer utiliza el parámetro SECRET_KEY para generar firmas. Puedes utilizar un secreto diferente pasándolo al constructor de la clase Signer:
>>> signer = Signer(key="my-other-secret")
>>> value = signer.sign("My string")
>>> value
'My string:o3DrrsT6JRB73t-HDymfDNbTSxfMlom2d8TiUlb1hWY'
Devuelve un firmante que utiliza key para generar firmas y sep para separar valores. sep no puede estar en el alfabeto base64 seguro. Este alfabeto contiene caracteres alfanuméricos, guiones y subrayados. algorithm debe ser un algoritmo admitido por hashlib, que tiene como valor predeterminado 'sha256'. fallback_keys es una lista de valores adicionales utilizados para validar datos firmados, con valor predeterminado SECRET_KEY_FALLBACKS.
salt¶Si no deseas que cada ocurrencia de una cadena particular tenga la misma firma hash, puedes utilizar el argumento opcional salt en la clase Signer. Utilizar un sal es semear la función de hash de firmado con tanto el sal como tu 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!'}
Utilizando sal de esta manera coloca las diferentes firmas en diferentes nombres de espacio. Una firma que proviene de un nombre de espacio (un valor de sal particular) no puede utilizarse para validar la misma cadena de texto plano en un nombre de espacio diferente que utiliza una configuración de sal diferente. El resultado es prevenir a un atacante de utilizar una cadena firmada generada en un lugar del código como entrada a otra pieza de código que está generando (y verificando) firmas utilizando una sal diferente.
A diferencia de tu SECRET_KEY, tu argumento de sal no necesita permanecer secreto.
TimestampSigner es una subclase de Signer que agrega un timestamp firmado al valor. Esto te permite confirmar que un valor firmado se creó dentro de un período de tiempo especificado:
>>> 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'
Verifica si value fue firmada hace menos de max_age segundos, en caso contrario levanta SignatureExpired. El parámetro max_age puede aceptar un entero o un objeto datetime.timedelta.
Codifica, opcionalmente comprime, agrega el timestamp actual y firma estructuras de datos complejas (por ejemplo, lista, tupla o diccionario).
Verifica si signed_obj fue firmada hace menos de max_age segundos, en caso contrario levanta SignatureExpired. El parámetro max_age puede aceptar un entero o un objeto datetime.timedelta.
Si deseas proteger una lista, tupla o diccionario puedes hacerlo utilizando los métodos sign_object() y unsign_object() del objeto Signer, o las funciones dumps() y loads() del módulo de firmado (que son atajos para TimestampSigner(salt=”django.core.signing”).sign_object()/unsign_object()). Estas utilizan la serialización JSON bajo la cubierta. La JSON garantiza que incluso si tu SECRET_KEY es robada, un atacante no podrá ejecutar comandos arbitrarios explotando el formato 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'}
Debido a la naturaleza de JSON (no hay una distinción nativa entre listas y tuplas) si pasas una tupla, obtendrás una lista desde signing.loads(object):
>>> from django.core import signing
>>> value = signing.dumps(("a", "b", "c"))
>>> signing.loads(value)
['a', 'b', 'c']
Devuelve cadena URL segura, firmada y comprimida en base64. La cadena JSON serializada se firma utilizando TimestampSigner.
may 31, 2026