Den gyllene regeln för säkerhet i webbapplikationer är att aldrig lita på data från källor som inte är betrodda. Ibland kan det vara användbart att skicka data genom ett icke betrott medium. Kryptografiskt signerade värden kan skickas genom en icke betrodd kanal i trygg förvissning om att eventuell manipulering kommer att upptäckas.
Django tillhandahåller både ett API på låg nivå för att signera värden och ett API på hög nivå för att ställa in och läsa signerade cookies, en av de vanligaste användningarna av signering i webbapplikationer.
Du kanske också tycker att det är bra att skriva under för följande:
Generering av URL:er för ”återställ mitt konto” som skickas till användare som har förlorat sitt lösenord.
Säkerställa att data som lagras i dolda formulärfält inte har manipulerats.
Generera hemliga URL:er för engångsbruk för att ge tillfällig tillgång till en skyddad resurs, t.ex. en nedladdningsbar fil som en användare har betalat för.
SECRET_KEY och SECRET_KEY_FALLBACKS¶När du skapar ett nytt Django-projekt med startproject, genereras filen settings.py automatiskt och får ett slumpmässigt SECRET_KEY-värde. Detta värde är nyckeln till att säkra signerade data - det är viktigt att du håller det säkert, annars kan angripare använda det för att generera sina egna signerade värden.
SECRET_KEY_FALLBACKS kan användas för att rotera hemliga nycklar. Värdena kommer inte att användas för att signera data, men om de anges kommer de att användas för att validera signerade data och måste hållas säkra.
Djangos signeringsmetoder finns i modulen django.core.signing. För att signera ett värde, instansiera först en Signer instans:
>>> from django.core.signing import Signer
>>> signer = Signer()
>>> value = signer.sign("My string")
>>> value
'My string:v9G-nxfz3iQGTXrePqYPlGvH79WTcIgj1QIQSUODTW0'
Signaturen läggs till i slutet av strängen, efter kolon. Du kan hämta originalvärdet med hjälp av metoden unsign:
>>> original = signer.unsign(value)
>>> original
'My string'
Om du skickar ett värde som inte är en sträng till sign, kommer värdet att tvingas till sträng innan det signeras, och unsign-resultatet kommer att ge dig strängvärdet:
>>> signed = signer.sign(2.5)
>>> original = signer.unsign(signed)
>>> original
'2.5'
Om du vill skydda en lista, tupel eller dictionary kan du göra det med hjälp av metoderna sign_object() och unsign_object():
>>> signed_obj = signer.sign_object({"message": "Hello!"})
>>> signed_obj
'eyJtZXNzYWdlIjoiSGVsbG8hIn0:bzb48DBkB-bwLaCnUVB75r5VAPUEpzWJPrTb80JMIXM'
>>> obj = signer.unsign_object(signed_obj)
>>> obj
{'message': 'Hello!'}
Se Skydd av komplexa datastrukturer för mer information.
Om signaturen eller värdet har ändrats på något sätt, kommer ett django.core.signing.BadSignature undantag att uppstå:
>>> from django.core import signing
>>> value += "m"
>>> try:
... original = signer.unsign(value)
... except signing.BadSignature:
... print("Tampering detected!")
...
Som standard använder klassen Signer inställningen SECRET_KEY för att generera signaturer. Du kan använda en annan hemlighet genom att skicka den till konstruktören för Signer:
>>> signer = Signer(key="my-other-secret")
>>> value = signer.sign("My string")
>>> value
'My string:o3DrrsT6JRB73t-HDymfDNbTSxfMlom2d8TiUlb1hWY'
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¶Om du inte vill att alla förekomster av en viss sträng ska ha samma signaturhash kan du använda det valfria argumentet salt till klassen Signer. Om du använder ett salt kommer den signerande hashfunktionen att seedas med både saltet och din 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.
Till skillnad från din SECRET_KEY behöver ditt saltargument inte vara hemligt.
TimestampSigner är en subklass av Signer som lägger till en signerad tidsstämpel till värdet. Detta gör att du kan bekräfta att ett signerat värde skapades inom en viss tidsperiod:
>>> 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'
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.
Koda, eventuellt komprimera, lägga till aktuell tidsstämpel och signera komplex datastruktur (t.ex. lista, tupel eller ordbok).
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.
Om du vill skydda en lista, tupel eller dictionary kan du göra det med hjälp av metoderna Signer.sign_object() och unsign_object(), eller signeringsmodulens dumps() eller loads() funktioner (som är förkortningar för TimestampSigner(salt='django.core.signing').sign_object()/unsign_object()). Dessa använder JSON-serialisering under huven. JSON säkerställer att även om din SECRET_KEY blir stulen kommer en angripare inte att kunna utföra godtyckliga kommandon genom att utnyttja pickle-formatet:
>>> 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'}
På grund av JSON:s natur (det finns ingen inbyggd skillnad mellan listor och tupler) kommer du att få en lista från signing.loads(object) om du skickar in en tupel:
>>> from django.core import signing
>>> value = signing.dumps(("a", "b", "c"))
>>> signing.loads(value)
['a', 'b', 'c']
Returnerar URL-säker, signerad base64-komprimerad JSON-sträng. Det serialiserade objektet signeras med hjälp av TimestampSigner.
dec. 03, 2025