demystify Flask app.secret_key

127

Jeśli app.secret_key nie jest ustawiona, Flask nie pozwoli ci ustawić ani uzyskać dostępu do słownika sesji.

To wszystko, co na ten temat mówi instrukcja obsługi kolb .

Jestem bardzo nowy w tworzeniu stron internetowych i nie mam pojęcia, jak / dlaczego działają jakiekolwiek zabezpieczenia. Chciałbym zrozumieć, co robi Flask pod maską.

  • Dlaczego Flask zmusza nas do tego secret_key właściwości?
  • W jaki sposób Flask wykorzystuje tę secret_keywłaściwość?
MOJA V
źródło

Odpowiedzi:

102

Wszystko, co wymaga szyfrowania (w celu zabezpieczenia przed manipulacją przez atakujących), wymaga ustawienia tajnego klucza. Dla tylko samego Kolby, że „coś” jest Sessionobiektem, ale inne rozszerzenia mogą korzystać z tej samej tajemnicy.

secret_keyjest tylko wartością ustawioną dla SECRET_KEYklucza konfiguracyjnego lub można ją ustawić bezpośrednio.

Sekcja Sesje w przewodniku Szybki start zawiera dobre, rozsądne porady na temat tego, jaki rodzaj klucza po stronie serwera należy ustawić.

Szyfrowanie opiera się na tajemnicach; jeśli nie ustawisz hasła po stronie serwera do użycia przez szyfrowanie, każdy będzie mógł złamać Twoje szyfrowanie; to jest jak hasło do twojego komputera. Sekret oraz dane do podpisania są używane do tworzenia ciągu podpisu, wartości trudnej do odtworzenia przy użyciu kryptograficznego algorytmu mieszania ; tylko jeśli masz dokładnie ten sam sekret i oryginalne dane, możesz odtworzyć tę wartość, pozwalając Flask wykryć, czy cokolwiek zostało zmienione bez pozwolenia. Ponieważ sekret nigdy nie jest dołączany do danych, które Flask wysyła do klienta, klient nie może manipulować danymi sesji i mieć nadzieję na utworzenie nowego, ważnego podpisu.

Flask używa itsdangerousbiblioteki do wykonywania całej ciężkiej pracy; sesje używają itsdangerous.URLSafeTimedSerializerklasy z dostosowanym serializatorem JSON.

Martijn Pieters
źródło
91

Poniższa odpowiedź dotyczy przede wszystkim Signed Cookies , czyli implementacji koncepcji sesji (używanej w aplikacjach internetowych). Flask oferuje zarówno zwykłe (niepodpisane) pliki cookie (przez request.cookiesi response.set_cookie()), jak i podpisane (przez flask.session). Odpowiedź składa się z dwóch części: pierwsza opisuje sposób generowania podpisanego pliku cookie, a druga jest przedstawiona w formie kontroli jakości, która dotyczy różnych aspektów schematu. Składnia użyta w przykładach to Python3, ale koncepcje odnoszą się również do poprzednich wersji.

Co to jest SECRET_KEY(lub jak utworzyć podpisany plik cookie)?

Podpisywanie plików cookie jest środkiem zapobiegawczym przeciwko manipulowaniu plikami cookie. Podczas procesu podpisywania pliku cookie SECRET_KEYjest on używany w sposób podobny do tego, jak „sól” byłaby używana do pomieszania hasła przed jego zahaszowaniem. Oto (szalenie) uproszczony opis pojęcia. Kod w przykładach ma charakter ilustracyjny. Wiele kroków zostało pominiętych i nie wszystkie funkcje faktycznie istnieją. Celem jest zapewnienie zrozumienia ogólnej idei, rzeczywiste wdrożenia będą nieco bardziej zaangażowane. Pamiętaj też, że Flask robi większość tego za Ciebie w tle. Tak więc, oprócz ustawiania wartości dla pliku cookie (za pośrednictwem interfejsu API sesji) i dostarczania pliku SECRET_KEY, nie tylko niezradzane jest ponowne wdrażanie tego samodzielnie, ale nie ma takiej potrzeby:

Podpis pliku cookie biedaka

Przed wysłaniem odpowiedzi do przeglądarki:

(1) Najpierw powstaje a SECRET_KEY. Powinien być znany tylko aplikacji i powinien być utrzymywany na względnie stałym poziomie podczas cyklu życia aplikacji, w tym podczas ponownego uruchamiania aplikacji.

# choose a salt, a secret string of bytes
>>> SECRET_KEY = 'my super secret key'.encode('utf8')

(2) utwórz plik 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) aby utworzyć podpis, dołącz (lub dodaj przed nim) SECRET_KEYciąg bajtów pliku cookie, a następnie wygeneruj skrót z tej kombinacji.

# 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) Teraz umieść podpis na jednym końcu contentpola oryginalnego pliku cookie.

# 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

i to właśnie jest wysyłane do klienta.

# add cookie to response
>>> response.set_cookie(cookie)
# send to browser --> 

Po otrzymaniu pliku cookie z przeglądarki:

(5) Kiedy przeglądarka zwraca ten plik cookie z powrotem na serwer, usuń podpis z pola pliku cookie, contentaby odzyskać oryginalny plik cookie.

# 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) Użyj oryginalnego pliku cookie z aplikacją, SECRET_KEYaby przeliczyć podpis, używając tej samej metody, co w kroku 3.

# recalculate signature using SECRET_KEY and original cookie
>>> cookie_bytes = str(cookie).encode('utf8')
>>> calculated_signature = sha1(cookie_bytes+SECRET_KEY).hexdigest()

(7) Porównaj obliczony wynik z podpisem wyskakującym z właśnie otrzymanego pliku cookie. Jeśli pasują, wiemy, że plik cookie nie został zmieniony. Ale jeśli nawet spacja została dodana do pliku cookie, podpisy nie będą pasować.

# if both signatures match, your cookie has not been modified
>>> good_cookie = popped_signature==calculated_signature

(8) Jeśli się nie zgadzają, możesz odpowiedzieć dowolną liczbą działań, zarejestrować zdarzenie, odrzucić plik cookie, wydać nowy, przekierować na stronę logowania itp.

>>> if not good_cookie:
...     security_log(cookie)

Kod uwierzytelniania wiadomości oparty na skrótach (HMAC)

Typ podpisu wygenerowanego powyżej, który wymaga tajnego klucza, aby zapewnić integralność niektórych treści, jest nazywany w kryptografii kodem uwierzytelniania wiadomości lub adresem MAC .

Sprecyzowałem wcześniej, że powyższy przykład jest nadmiernym uproszczeniem tej koncepcji i że nie jest dobrym pomysłem wdrażanie własnego podpisu. Dzieje się tak, ponieważ algorytm używany do podpisywania plików cookie w Flasku nazywa się HMAC i jest nieco bardziej zaangażowany niż powyższy prosty krok po kroku. Ogólna idea jest taka sama, ale z powodów wykraczających poza zakres tej dyskusji seria obliczeń jest odrobinę bardziej złożona. Jeśli nadal jesteś zainteresowany stworzeniem majsterkowania, jak to zwykle bywa, Python ma kilka modułów, które pomogą Ci zacząć :) oto blok startowy:

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()

Dokumentacja dla hmac i hashlib .


„Demistyfikacja” SECRET_KEY:)

Co to jest „podpis” w tym kontekście?

Jest to metoda zapewniająca, że ​​niektóre treści nie zostały zmodyfikowane przez nikogo poza osobą lub podmiotem do tego upoważnionym.

Jedną z najprostszych form podpisu jest „ suma kontrolna ”, która po prostu sprawdza, czy dwie części danych są takie same. Na przykład podczas instalowania oprogramowania ze źródła ważne jest, aby najpierw potwierdzić, że Twoja kopia kodu źródłowego jest identyczna z kopią jego autora. Typowym podejściem do tego jest uruchomienie źródła za pomocą kryptograficznej funkcji skrótu i ​​porównanie wyników z sumą kontrolną opublikowaną na stronie głównej projektu.

Załóżmy na przykład, że masz zamiar pobrać źródło projektu w pliku gzip z serwera lustrzanego. Suma kontrolna SHA1 opublikowana na stronie internetowej projektu to „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....

Oba skróty są takie same, wiesz, że masz identyczną kopię.

Co to jest plik cookie?

Obszerna dyskusja na temat plików cookie wykraczałaby poza zakres tego pytania. Przedstawiam tutaj przegląd, ponieważ minimalne zrozumienie może być przydatne, aby lepiej zrozumieć, jak i dlaczego SECRET_KEYjest przydatne. Gorąco zachęcam do dalszych osobistych lektur na temat plików cookie HTTP.

Powszechną praktyką w aplikacjach internetowych jest używanie klienta (przeglądarki internetowej) jako niewielkiej pamięci podręcznej. Pliki cookie są jedną z realizacji tej praktyki. Plik cookie to zazwyczaj pewne dane dodawane przez serwer do odpowiedzi HTTP za pośrednictwem jego nagłówków. Jest przechowywany przez przeglądarkę, która następnie odsyła go z powrotem do serwera podczas wysyłania żądań, również za pośrednictwem nagłówków HTTP. Dane zawarte w pliku cookie mogą służyć do emulacji tzw Stanu, iluzja, że ​​serwer utrzymuje ciągłe połączenie z klientem. Tylko w tym przypadku zamiast okablowania utrzymującego połączenie „przy życiu” masz po prostu migawki stanu aplikacji po tym, jak obsłużyła ona żądanie klienta. Te migawki są przenoszone między klientem a serwerem. Po otrzymaniu żądania serwer najpierw odczytuje zawartość pliku cookie, aby przywrócić kontekst swojej rozmowy z klientem. Następnie obsługuje żądanie w tym kontekście i przed zwróceniem odpowiedzi klientowi aktualizuje plik cookie. W ten sposób zostaje zachowana iluzja trwającej sesji.

Jak wygląda plik cookie?

Typowy plik cookie wyglądałby tak:

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

Pliki cookie są łatwe do odczytania w każdej nowoczesnej przeglądarce. Na przykład w przeglądarce Firefox przejdź do Preferencje> Prywatność> Historia> usuń poszczególne pliki cookie .

contentPole jest najbardziej odpowiednie dla danej aplikacji. Inne pola zawierają głównie instrukcje meta, aby określić różne zakresy wpływu.

Po co w ogóle używać plików cookie?

Krótka odpowiedź to wydajność. Korzystanie z plików cookie minimalizuje potrzebę wyszukiwania rzeczy w różnych magazynach danych (pamięci podręczne, pliki, bazy danych itp.), Przyspieszając w ten sposób działanie po stronie aplikacji serwera. Należy pamiętać, że im większy plik cookie, tym większy ładunek w sieci, więc to, co zapisujesz podczas wyszukiwania bazy danych na serwerze, możesz stracić w sieci. Zastanów się dokładnie, co umieścić w swoich plikach cookie.

Dlaczego pliki cookie miałyby być podpisywane?

Pliki cookie są używane do przechowywania wszelkiego rodzaju informacji, z których niektóre mogą być bardzo wrażliwe. Z natury nie są one również bezpieczne i wymagają podjęcia szeregu dodatkowych środków ostrożności, aby w jakikolwiek sposób zostały uznane za bezpieczne dla obu stron, klienta i serwera. Podpisywanie plików cookie w szczególności rozwiązuje problem, przy którym można majstrować podczas prób oszukania aplikacji serwerowych. Istnieją inne sposoby ograniczania innych rodzajów luk, zachęcam do przeczytania więcej o plikach cookie.

Jak można majstrować przy ciasteczku?

Pliki cookie znajdują się na kliencie w formie tekstowej i można je edytować bez wysiłku. Plik cookie otrzymany przez Twoją aplikację serwera mógł zostać zmodyfikowany z wielu powodów, z których niektóre mogą nie być niewinne. Wyobraź sobie aplikację internetową, która przechowuje informacje o uprawnieniach swoich użytkowników w plikach cookie i przyznaje uprawnienia na podstawie tych informacji. Jeśli plik cookie nie jest odporny na majsterkowanie, każdy może zmodyfikować swój plik, aby podnieść jego status z „role = visitor” do „role = admin”, a aplikacja nie byłaby mądrzejsza.

Dlaczego SECRET_KEYpodpisywanie plików cookie jest konieczne?

Weryfikacja plików cookie różni się nieco od weryfikacji kodu źródłowego w sposób opisany wcześniej. W przypadku kodu źródłowego oryginalnym autorem jest powiernik i właściciel referencyjnego odcisku palca (sumy kontrolnej), który będzie publicznie dostępny. Nie ufasz kodowi źródłowemu, ale ufasz publicznemu podpisowi. Aby zweryfikować swoją kopię źródła, po prostu chcesz, aby obliczony hash był zgodny z publicznym hashem.

Jednak w przypadku pliku cookie aplikacja nie śledzi podpisu, tylko go śledzi SECRET_KEY. To SECRET_KEYjest referencyjny odcisk palca. Pliki cookie są przesyłane z podpisem, który twierdzi, że jest legalny. Legalność oznacza tutaj, że podpis został wystawiony przez właściciela ciasteczka, czyli aplikację, aw tym przypadku jest to oświadczenie, że nie ufasz i musisz sprawdzić podpis pod kątem ważności. Aby to zrobić, musisz dołączyć do podpisu element, który jest znany tylko Tobie, to jest plik SECRET_KEY. Ktoś może zmienić plik cookie, ale ponieważ nie ma tajnego składnika do prawidłowego obliczenia prawidłowego podpisu, nie może go sfałszować. Jak wspomniano nieco wcześniej, ten rodzaj odcisków palców, w którym na górze sumy kontrolnej znajduje się również tajny klucz,

A co z sesjami?

Sesje w ich klasycznej implementacji to pliki cookie, które zawierają tylko identyfikator w contentterenie, plik session_id. Cel sesji jest dokładnie taki sam, jak podpisane pliki cookie, tj. Zapobieganie manipulowaniu plikami cookie. Sesje klasyczne mają jednak inne podejście. Po otrzymaniu pliku cookie sesji serwer używa identyfikatora do wyszukiwania danych sesji we własnej pamięci lokalnej, którą może być baza danych, plik lub czasami pamięć podręczna w pamięci. Plik cookie sesji zazwyczaj wygasa po zamknięciu przeglądarki. Ze względu na krok wyszukiwania w pamięci lokalnej ta implementacja sesji zazwyczaj powoduje spadek wydajności. Podpisane pliki cookie stają się preferowaną alternatywą i w ten sposób implementowane są sesje Flask. Innymi słowy, sesje Flask topodpisane pliki cookie, a aby używać podpisanych plików cookie w usłudze Flask, wystarczy użyć jego Sessioninterfejsu API.

Dlaczego nie zaszyfrować plików cookie?

Czasami zawartość plików cookie może być zaszyfrowana przed podpisaniem . Dzieje się tak, jeśli zostaną uznane za zbyt wrażliwe, aby były widoczne w przeglądarce (szyfrowanie ukrywa zawartość). Samo podpisanie plików cookie odpowiada jednak innym potrzebom, takim, w którym istnieje chęć zachowania pewnego stopnia widoczności i użyteczności plików cookie w przeglądarce, jednocześnie zapobiegając ingerencji w nie.

Co się stanie, jeśli zmienię SECRET_KEY?

Zmieniając ustawienia SECRET_KEY, unieważniasz wszystkie pliki cookie podpisane poprzednim kluczem. Gdy aplikacja otrzyma żądanie z ciasteczkiem podpisanym poprzednim SECRET_KEY, spróbuje obliczyć podpis nowym SECRET_KEY, a oba podpisy nie będą pasować, ten plik cookie i wszystkie jego dane zostaną odrzucone, będzie tak, jakby przeglądarka łączy się z serwerem po raz pierwszy. Użytkownicy zostaną wylogowani, a ich stare pliki cookie zostaną zapomniane, a także wszystko, co jest w nich przechowywane. Zwróć uwagę, że różni się to od sposobu obsługi wygasłego pliku cookie. Dzierżawa wygasłego pliku cookie może zostać przedłużona, jeśli jego podpis zostanie sprawdzony. Nieprawidłowy podpis oznacza po prostu zwykły nieprawidłowy plik cookie.

Jeśli więc nie chcesz unieważnić wszystkich podpisanych plików cookie, spróbuj zachować SECRET_KEYto samo przez dłuższy czas.

Co jest dobre SECRET_KEY?

Tajny klucz powinien być trudny do odgadnięcia. Dokumentacja dotycząca sesji zawiera dobry przepis na losowe generowanie kluczy:

>>> import os
>>> os.urandom(24)
'\xfd{H\xe5<\x95\xf9\xe3\x96.5\xd1\x01O<!\xd5\xa2\xa0\x9fR"\xa1\xa8'

Kopiujesz klucz i wklejasz go do pliku konfiguracyjnego jako wartość SECRET_KEY.

Oprócz użycia losowo wygenerowanego klucza, możesz użyć złożonego zestawu słów, liczb i symboli, być może ułożonych w zdaniu znanym tylko tobie, zakodowanym w postaci bajtów.

Czy nie ustawić SECRET_KEYbezpośrednio z funkcją, która generuje inny klucz za każdym razem to się nazywa. Na przykład nie rób tego:

# this is not good
SECRET_KEY = random_key_generator()

Za każdym razem, gdy aplikacja zostanie uruchomiona ponownie, otrzyma nowy klucz, unieważniając w ten sposób poprzedni.

Zamiast tego otwórz interaktywną powłokę Pythona i wywołaj funkcję w celu wygenerowania klucza, a następnie skopiuj i wklej go do pliku config.

Michael Ekoka
źródło