Die folgende Antwort bezieht sich hauptsächlich auf signierte Cookies , eine Implementierung des Sitzungskonzepts (wie es in Webanwendungen verwendet wird). Flask bietet sowohl normale (nicht signierte) Cookies (via request.cookies
und response.set_cookie()
) als auch signierte Cookies (via flask.session
) an. Die Antwort besteht aus zwei Teilen: Der erste beschreibt, wie ein signiertes Cookie generiert wird, und der zweite Teil wird in Form einer Qualitätssicherung dargestellt, die verschiedene Aspekte des Schemas behandelt. Die für die Beispiele verwendete Syntax lautet Python3, die Konzepte gelten jedoch auch für frühere Versionen.
Was ist SECRET_KEY
(oder wie erstelle ich ein signiertes Cookie)?
Das Signieren von Cookies ist eine vorbeugende Maßnahme gegen das Manipulieren von Cookies. Während des Signierens eines Cookies SECRET_KEY
wird das auf ähnliche Weise verwendet, wie ein "Salz" verwendet würde, um ein Kennwort vor dem Hashing zu verwirren. Hier ist eine (wild) vereinfachte Beschreibung des Konzepts. Der Code in den Beispielen soll veranschaulichend sein. Viele der Schritte wurden weggelassen und nicht alle Funktionen existieren tatsächlich. Ziel ist es, ein Verständnis für die allgemeine Idee zu vermitteln. Die tatsächlichen Implementierungen sind etwas komplizierter. Denken Sie auch daran, dass Flask das meiste im Hintergrund für Sie erledigt. Neben dem Festlegen von Werten für Ihr Cookie (über die Sitzungs-API) und dem Bereitstellen von a SECRET_KEY
ist es nicht nur nicht ratsam, dies selbst erneut zu implementieren, sondern es besteht auch keine Notwendigkeit, dies zu tun:
Die Cookie-Signatur eines armen Mannes
Vor dem Senden einer Antwort an den Browser:
(1) Zunächst SECRET_KEY
wird a festgelegt. Es sollte nur der Anwendung bekannt sein und während des Lebenszyklus der Anwendung, einschließlich durch Neustarts der Anwendung, relativ konstant gehalten werden.
# choose a salt, a secret string of bytes
>>> SECRET_KEY = 'my super secret key'.encode('utf8')
(2) Erstellen Sie ein Cookie
>>> cookie = make_cookie(
... name='_profile',
... content='uid=382|membership=regular',
... ...
... expires='July 1 2030...'
... )
>>> print(cookie)
name: _profile
content: uid=382|membership=regular...
...
...
expires: July 1 2030, 1:20:40 AM UTC
(3) Um eine Signatur zu erstellen, fügen Sie SECRET_KEY
die Zeichenfolge an die Cookie-Byte-Zeichenfolge an (oder stellen Sie sie vor) , und generieren Sie dann aus dieser Kombination einen Hash.
# encode and salt the cookie, then hash the result
>>> cookie_bytes = str(cookie).encode('utf8')
>>> signature = sha1(cookie_bytes+SECRET_KEY).hexdigest()
>>> print(signature)
7ae0e9e033b5fa53aa....
(4) Bringen Sie nun die Signatur an einem Ende des content
Feldes des Original-Cookies an.
# include signature as part of the cookie
>>> cookie.content = cookie.content + '|' + signature
>>> print(cookie)
name: _profile
content: uid=382|membership=regular|7ae0e9... <--- signature
domain: .example.com
path: /
send for: Encrypted connections only
expires: July 1 2030, 1:20:40 AM UTC
und genau das wird an den Kunden gesendet.
# add cookie to response
>>> response.set_cookie(cookie)
# send to browser -->
Nach Erhalt des Cookies vom Browser:
(5) Wenn der Browser dieses Cookie an den Server zurückgibt, entfernen Sie die Signatur aus dem content
Feld des Cookies , um das ursprüngliche Cookie zurückzugewinnen.
# Upon receiving the cookie from browser
>>> cookie = request.get_cookie()
# pop the signature out of the cookie
>>> (cookie.content, popped_signature) = cookie.content.rsplit('|', 1)
(6) Verwenden Sie das Original-Cookie mit den Anwendungen, SECRET_KEY
um die Signatur mit derselben Methode wie in Schritt 3 neu zu berechnen.
# recalculate signature using SECRET_KEY and original cookie
>>> cookie_bytes = str(cookie).encode('utf8')
>>> calculated_signature = sha1(cookie_bytes+SECRET_KEY).hexdigest()
(7) Vergleichen Sie das berechnete Ergebnis mit der Signatur, die zuvor aus dem gerade erhaltenen Cookie herausgesprungen ist. Wenn sie übereinstimmen, wissen wir, dass der Cookie nicht durcheinander gebracht wurde. Wenn dem Cookie jedoch nur ein Leerzeichen hinzugefügt wurde, stimmen die Signaturen nicht überein.
# if both signatures match, your cookie has not been modified
>>> good_cookie = popped_signature==calculated_signature
(8) Wenn sie nicht übereinstimmen, können Sie mit einer beliebigen Anzahl von Aktionen antworten, das Ereignis protokollieren, das Cookie verwerfen, ein neues ausgeben, auf eine Anmeldeseite umleiten usw.
>>> if not good_cookie:
... security_log(cookie)
Hash-basierter Nachrichtenauthentifizierungscode (HMAC)
Die oben generierte Art der Signatur, für die ein geheimer Schlüssel erforderlich ist, um die Integrität einiger Inhalte sicherzustellen, wird in der Kryptografie als Nachrichtenauthentifizierungscode oder MAC bezeichnet .
Ich habe zuvor angegeben, dass das obige Beispiel eine übermäßige Vereinfachung dieses Konzepts darstellt und dass es keine gute Idee ist, eine eigene Signatur zu implementieren. Dies liegt daran, dass der Algorithmus zum Signieren von Cookies in Flask als HMAC bezeichnet wird und etwas komplizierter ist als die oben beschriebenen einfachen schrittweisen Schritte. Die allgemeine Idee ist dieselbe, aber aus Gründen, die über den Rahmen dieser Diskussion hinausgehen, sind die Berechnungsreihen etwas komplexer. Wenn Sie immer noch daran interessiert sind, ein DIY herzustellen, wie es normalerweise der Fall ist, hat Python einige Module, die Ihnen den Einstieg erleichtern :) Hier ist ein Startblock:
import hmac
import hashlib
def create_signature(secret_key, msg, digestmod=None):
if digestmod is None:
digestmod = hashlib.sha1
mac = hmac.new(secret_key, msg=msg, digestmod=digestmod)
return mac.digest()
Die Dokumentation für hmac und hashlib .
Die "Entmystifizierung" von SECRET_KEY
:)
Was ist in diesem Zusammenhang eine "Signatur"?
Auf diese Weise wird sichergestellt, dass einige Inhalte nur von einer dazu befugten Person oder Organisation geändert wurden.
Eine der einfachsten Formen der Signatur ist die " Prüfsumme ", mit der lediglich überprüft wird, ob zwei Daten identisch sind. Wenn Sie beispielsweise Software aus dem Quellcode installieren, müssen Sie zunächst sicherstellen, dass Ihre Kopie des Quellcodes mit der des Autors identisch ist. Ein üblicher Ansatz hierfür besteht darin, die Quelle über eine kryptografische Hash-Funktion auszuführen und die Ausgabe mit der auf der Homepage des Projekts veröffentlichten Prüfsumme zu vergleichen.
Angenommen, Sie möchten die Quelle eines Projekts in einer komprimierten Datei von einem Webspiegel herunterladen. Die auf der Projektwebseite veröffentlichte SHA1-Prüfsumme lautet 'eb84e8da7ca23e9f83 ....'
# so you get the code from the mirror
download https://mirror.example-codedump.com/source_code.tar.gz
# you calculate the hash as instructed
sha1(source_code.tar.gz)
> eb84e8da7c....
Beide Hashes sind gleich, Sie wissen, dass Sie eine identische Kopie haben.
Was ist ein Cookie?
Eine ausführliche Diskussion über Cookies würde den Rahmen dieser Frage sprengen. Ich gebe hier einen Überblick, da ein minimales Verständnis hilfreich sein kann, um besser zu verstehen, wie und warum dies SECRET_KEY
nützlich ist. Ich empfehle Ihnen dringend, einige persönliche Lesungen zu HTTP-Cookies vorzunehmen.
In Webanwendungen wird häufig der Client (Webbrowser) als kompakter Cache verwendet. Cookies sind eine Implementierung dieser Praxis. Ein Cookie besteht normalerweise aus Daten, die der Server über seine Header zu einer HTTP-Antwort hinzufügt. Es wird vom Browser gespeichert, der es anschließend bei der Ausgabe von Anforderungen an den Server zurücksendet, auch über HTTP-Header. Die in einem Cookie enthaltenen Daten können verwendet werden, um die sogenannte Statefulness zu emulieren, die Illusion, dass der Server eine laufende Verbindung mit dem Client aufrechterhält. Nur in diesem Fall haben Sie anstelle eines Kabels, um die Verbindung "am Leben zu erhalten", einfach Snapshots des Status der Anwendung, nachdem sie die Anforderung eines Clients bearbeitet hat. Diese Schnappschüsse werden zwischen Client und Server hin und her übertragen. Nach Erhalt einer Anforderung liest der Server zuerst den Inhalt des Cookies, um den Kontext seiner Konversation mit dem Client wiederherzustellen. Anschließend wird die Anforderung in diesem Kontext verarbeitet und das Cookie aktualisiert, bevor die Antwort an den Client zurückgegeben wird. Die Illusion einer laufenden Sitzung bleibt somit erhalten.
Wie sieht ein Cookie aus?
Ein typischer Cookie würde folgendermaßen aussehen:
name: _profile
content: uid=382|status=genie
domain: .example.com
path: /
send for: Encrypted connections only
expires: July 1 2030, 1:20:40 AM UTC
Cookies sind in jedem modernen Browser trivial zu lesen. Gehen Sie in Firefox beispielsweise zu Einstellungen> Datenschutz> Verlauf> Einzelne Cookies entfernen .
Das content
Feld ist für die Anwendung am relevantesten. Andere Felder enthalten meist Meta-Anweisungen, um verschiedene Einflussbereiche anzugeben.
Warum überhaupt Cookies verwenden?
Die kurze Antwort lautet Leistung. Durch die Verwendung von Cookies wird die Notwendigkeit minimiert, in verschiedenen Datenspeichern (Speichercaches, Dateien, Datenbanken usw.) nachzuschlagen, wodurch die Arbeit auf der Seite der Serveranwendung beschleunigt wird. Beachten Sie, dass die Nutzlast über das Netzwerk umso höher ist, je größer das Cookie ist. Was Sie also bei der Datenbanksuche auf dem Server speichern, kann über das Netzwerk verloren gehen. Überlegen Sie genau, was Sie in Ihre Cookies aufnehmen möchten.
Warum müssen Cookies signiert werden?
Cookies werden verwendet, um alle Arten von Informationen zu speichern, von denen einige sehr sensibel sein können. Sie sind von Natur aus auch nicht sicher und erfordern, dass eine Reihe von zusätzlichen Vorsichtsmaßnahmen getroffen werden, um für beide Parteien, den Client und den Server, in irgendeiner Weise als sicher zu gelten. Das Signieren von Cookies behebt speziell das Problem, mit dem sie beim Versuch, Serveranwendungen zu täuschen, bearbeitet werden können. Es gibt andere Maßnahmen, um andere Arten von Sicherheitslücken zu mindern. Ich empfehle Ihnen, mehr über Cookies zu erfahren.
Wie kann ein Cookie manipuliert werden?
Cookies befinden sich in Textform auf dem Client und können mühelos bearbeitet werden. Ein von Ihrer Serveranwendung empfangenes Cookie wurde möglicherweise aus verschiedenen Gründen geändert, von denen einige möglicherweise nicht unschuldig sind. Stellen Sie sich eine Webanwendung vor, die Berechtigungsinformationen über ihre Benutzer in Cookies speichert und Berechtigungen basierend auf diesen Informationen gewährt. Wenn der Cookie nicht bastelsicher ist, kann jeder seinen ändern, um seinen Status von "Rolle = Besucher" auf "Rolle = Administrator" zu erhöhen, und die Anwendung wäre nicht klüger.
Warum ist es SECRET_KEY
notwendig, Cookies zu signieren?
Das Überprüfen von Cookies unterscheidet sich ein wenig vom Überprüfen des Quellcodes wie zuvor beschrieben. Im Falle des Quellcodes ist der ursprüngliche Autor der Treuhänder und Eigentümer des Referenzfingerabdrucks (der Prüfsumme), der öffentlich zugänglich gemacht wird. Was Sie nicht vertrauen, ist der Quellcode, aber Sie vertrauen der öffentlichen Signatur. Um Ihre Kopie der Quelle zu überprüfen, möchten Sie einfach, dass Ihr berechneter Hash mit dem öffentlichen Hash übereinstimmt.
Im Falle eines Cookies verfolgt die Anwendung jedoch nicht die Signatur, sondern deren Signatur SECRET_KEY
. Das SECRET_KEY
ist der Referenzfingerabdruck. Cookies werden mit einer Unterschrift versehen, die sie für legitim halten. Legitimität bedeutet hier, dass die Signatur vom Inhaber des Cookies, dh der Anwendung, ausgestellt wurde. In diesem Fall ist es die Behauptung, dass Sie nicht vertrauen und die Signatur auf Gültigkeit prüfen müssen. Dazu müssen Sie ein Element in die Signatur aufnehmen, das nur Ihnen bekannt ist SECRET_KEY
. Jemand kann ein Cookie ändern, aber da er nicht die geheime Zutat hat, um eine gültige Signatur richtig zu berechnen, kann er sie nicht fälschen. Wie bereits erwähnt, wird bei dieser Art des Fingerabdrucks zusätzlich zur Prüfsumme auch ein geheimer Schlüssel bereitgestellt.
Was ist mit Sitzungen?
Sitzungen in ihrer klassischen Implementierung sind Cookies, die nur eine ID im content
Feld tragen, die session_id
. Der Zweck von Sitzungen ist genau der gleiche wie bei signierten Cookies, dh um eine Manipulation von Cookies zu verhindern. Klassische Sessions haben jedoch einen anderen Ansatz. Beim Empfang eines Sitzungscookies verwendet der Server die ID, um die Sitzungsdaten in seinem eigenen lokalen Speicher nachzuschlagen. Dies kann eine Datenbank, eine Datei oder manchmal ein Cache im Speicher sein. Das Sitzungscookie läuft normalerweise ab, wenn der Browser geschlossen wird. Aufgrund des lokalen Speichersuchschritts führt diese Implementierung von Sitzungen normalerweise zu einem Leistungseinbruch. Signierte Cookies werden zu einer bevorzugten Alternative, und so werden die Sitzungen von Flask implementiert. Mit anderen Worten, Flask-Sitzungen sindsignierte Cookies und um signierte Cookies in Flask zu verwenden, verwenden Sie einfach die Session
API.
Warum nicht auch die Cookies verschlüsseln?
Manchmal kann der Inhalt von Cookies verschlüsselt werden, bevor er ebenfalls signiert wird . Dies geschieht, wenn sie als zu empfindlich angesehen werden, um im Browser sichtbar zu sein (die Verschlüsselung verbirgt den Inhalt). Das einfache Signieren von Cookies spricht jedoch ein anderes Bedürfnis an, bei dem es darum geht, ein gewisses Maß an Sichtbarkeit und Verwendbarkeit von Cookies im Browser aufrechtzuerhalten und gleichzeitig zu verhindern, dass sie sich einmischen.
Was passiert, wenn ich das ändere SECRET_KEY
?
Durch Ändern der SECRET_KEY
Option werden alle mit dem vorherigen Schlüssel signierten Cookies ungültig . Wenn die Anwendung eine Anfrage mit einem Cookie erhält, das mit einem vorherigen signiert wurde SECRET_KEY
, versucht sie, die Signatur mit dem neuen zu berechnen SECRET_KEY
, und beide Signaturen stimmen nicht überein. Dieses Cookie und alle seine Daten werden abgelehnt. Es ist, als ob Der Browser stellt zum ersten Mal eine Verbindung zum Server her. Benutzer werden abgemeldet und ihr altes Cookie wird vergessen, zusammen mit allem, was darin gespeichert ist. Beachten Sie, dass sich dies von der Art und Weise unterscheidet, wie ein abgelaufenes Cookie behandelt wird. Bei einem abgelaufenen Cookie kann der Mietvertrag verlängert werden, wenn seine Signatur ausgecheckt wird. Eine ungültige Signatur impliziert lediglich ein einfaches ungültiges Cookie.
Wenn Sie also nicht alle signierten Cookies ungültig machen möchten, versuchen Sie, SECRET_KEY
diese für längere Zeiträume beizubehalten.
Was ist gut SECRET_KEY
?
Ein geheimer Schlüssel sollte schwer zu erraten sein. Die Dokumentation zu Sitzungen enthält ein gutes Rezept für die zufällige Schlüsselgenerierung:
>>> import os
>>> os.urandom(24)
'\xfd{H\xe5<\x95\xf9\xe3\x96.5\xd1\x01O<!\xd5\xa2\xa0\x9fR"\xa1\xa8'
Sie kopieren den Schlüssel und fügen ihn als Wert von in Ihre Konfigurationsdatei ein SECRET_KEY
.
Ohne einen zufällig generierten Schlüssel zu verwenden, könnten Sie eine komplexe Zusammenstellung von Wörtern, Zahlen und Symbolen verwenden, die möglicherweise in einem Satz angeordnet sind, der nur Ihnen bekannt ist und in Byteform codiert ist.
Sie nicht setzen die SECRET_KEY
direkt mit einer Funktion , die einen anderen Schlüssel jedes Mal erzeugt er genannt wird . Tun Sie dies beispielsweise nicht:
# this is not good
SECRET_KEY = random_key_generator()
Jedes Mal, wenn Ihre Anwendung neu gestartet wird, erhält sie einen neuen Schlüssel, wodurch der vorherige ungültig wird.
Öffnen Sie stattdessen eine interaktive Python-Shell und rufen Sie die Funktion zum Generieren des Schlüssels auf. Kopieren Sie ihn dann und fügen Sie ihn in die Konfiguration ein.