demystify Flask app.secret_key


127

Se app.secret_keynon impostato, Flask non ti consentirà di impostare o accedere al dizionario di sessione.

Questo è tutto ciò che la guida dell'utente del pallone ha da dire sull'argomento.

Sono molto nuovo nello sviluppo web e non ho idea di come / perché funzioni di sicurezza. Vorrei capire cosa sta facendo Flask sotto il cofano.

  • Perché Flask ci costringe a impostare questa secret_keyproprietà?
  • In che modo Flask utilizza la secret_keyproprietà?

Risposte:


102

Tutto ciò che richiede la crittografia (per la sicurezza contro la manomissione da parte di utenti malintenzionati) richiede l'impostazione della chiave segreta. Per appena Flask in sé, che 'qualsiasi cosa' è l' Sessionoggetto, ma altre estensioni può fare uso dello stesso segreto.

secret_keyè semplicemente il valore impostato per la SECRET_KEYchiave di configurazione oppure è possibile impostarlo direttamente.

La sezione Sessioni della Guida introduttiva offre buoni e sani consigli su quale tipo di segreto lato server dovresti impostare.

La crittografia si basa su segreti; se non hai impostato un segreto sul lato server per la crittografia da utilizzare, tutti sarebbero in grado di violarla; è come la password del tuo computer. Il segreto più i dati da firmare sono usati per creare una stringa di firma, un valore difficile da ricreare usando un algoritmo di hash crittografico ; solo se hai lo stesso segreto esatto e i dati originali puoi ricreare questo valore, consentendo a Flask di rilevare se qualcosa è stato modificato senza autorizzazione. Poiché il segreto non è mai incluso nei dati inviati da Flask al client, un client non può manomettere i dati della sessione e sperare di produrre una nuova firma valida.

Flask usa la itsdangerouslibreria per fare tutto il duro lavoro; le sessioni utilizzano la itsdangerous.URLSafeTimedSerializerclasse con un serializzatore JSON personalizzato.


91

La risposta di seguito riguarda principalmente i cookie firmati , un'implementazione del concetto di sessioni (utilizzato nelle applicazioni Web). Flask offre sia cookie normali (non firmati) (via request.cookiese response.set_cookie()) sia cookie firmati (via flask.session). La risposta ha due parti, la prima descrive come viene generato un cookie firmato e la seconda viene presentata sotto forma di un QA che affronta diversi aspetti dello schema. La sintassi utilizzata per gli esempi è Python3, ma i concetti si applicano anche alle versioni precedenti.

Che cos'è SECRET_KEY(o come creare un cookie firmato)?

La firma dei cookie è una misura preventiva contro la manomissione dei cookie. Durante il processo di firma di un cookie, SECRET_KEYviene utilizzato in modo simile al modo in cui un "sale" verrebbe utilizzato per confondere una password prima di eseguire l'hashing. Ecco una descrizione (selvaggiamente) semplificata del concetto. Il codice negli esempi è pensato per essere illustrativo. Molti dei passaggi sono stati omessi e in realtà non tutte le funzioni esistono. L'obiettivo qui è fornire una comprensione dell'idea generale, le implementazioni effettive saranno un po 'più coinvolte. Inoltre, tieni presente che Flask fa la maggior parte di questo per te in background. Quindi, oltre a impostare i valori per il tuo cookie (tramite l'API di sessione) e fornire un SECRET_KEY, non è solo sconsigliato reimplementarlo da solo, ma non è necessario farlo:

Firma dei biscotti di un povero

Prima di inviare una risposta al browser:

(1) In primo luogo SECRET_KEYè stabilito. Dovrebbe essere noto solo all'applicazione e dovrebbe essere mantenuto relativamente costante durante il ciclo di vita dell'applicazione, anche attraverso i riavvii dell'applicazione.

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

(2) crea un 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) per creare una firma, aggiungere (o anteporre) la SECRET_KEYstringa di byte del cookie, quindi generare un hash da quella combinazione.

# 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) Ora apponi la firma a un'estremità del contentcampo del cookie originale.

# 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

e questo è ciò che viene inviato al client.

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

Alla ricezione del cookie dal browser:

(5) Quando il browser restituisce questo cookie al server, rimuovere la firma dal contentcampo del cookie per ripristinare il cookie originale.

# 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) Utilizzare il cookie originale con l'applicazione SECRET_KEYper ricalcolare la firma utilizzando lo stesso metodo del passaggio 3.

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

(7) Confronta il risultato calcolato con la firma precedentemente estratta dal cookie appena ricevuto. Se corrispondono, sappiamo che il cookie non è stato danneggiato. Ma se anche solo uno spazio è stato aggiunto al cookie, le firme non corrisponderanno.

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

(8) Se non corrispondono, puoi rispondere con qualsiasi numero di azioni, registrare l'evento, scartare il cookie, emetterne uno nuovo, reindirizzare a una pagina di accesso, ecc.

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

Codice di autenticazione dei messaggi basato su hash (HMAC)

Il tipo di firma generato sopra che richiede una chiave segreta per garantire l'integrità di alcuni contenuti viene chiamato nella crittografia un codice di autenticazione dei messaggi o MAC .

Ho specificato in precedenza che l'esempio sopra è una semplificazione eccessiva di quel concetto e che non era una buona idea implementare la propria firma. Questo perché l'algoritmo utilizzato per firmare i cookie in Flask si chiama HMAC ed è un po 'più coinvolto rispetto al precedente semplice passo per passo. L'idea generale è la stessa, ma a causa di ragioni che esulano dallo scopo di questa discussione, la serie di calcoli è un po 'più complessa. Se sei ancora interessato a creare un fai-da-te, come di solito accade, Python ha alcuni moduli per aiutarti a iniziare :) ecco un blocco di partenza:

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

La documentazione per hmac e hashlib .


La "demistificazione" di SECRET_KEY:)

Che cos'è una "firma" in questo contesto?

È un metodo per garantire che alcuni contenuti non siano stati modificati da persone diverse da una persona o entità autorizzata a farlo.

Una delle forme più semplici di firma è il " checksum ", che verifica semplicemente che due parti di dati siano uguali. Ad esempio, quando si installa il software dal sorgente è importante confermare innanzitutto che la propria copia del codice sorgente è identica a quella dell'autore. Un approccio comune per fare ciò è eseguire la sorgente attraverso una funzione di hash crittografica e confrontare l'output con il checksum pubblicato nella home page del progetto.

Supponiamo, ad esempio, che stai per scaricare la fonte di un progetto in un file compresso da un web mirror. Il checksum SHA1 pubblicato sulla pagina web del progetto è "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....

Entrambi gli hash sono uguali, sai che hai una copia identica.

Che cos'è un cookie?

Un'ampia discussione sui cookie andrebbe oltre lo scopo di questa domanda. Fornisco una panoramica qui poiché una comprensione minima può essere utile per comprendere meglio come e perché SECRET_KEYè utile. Ti incoraggio vivamente a dare seguito ad alcune letture personali sui cookie HTTP.

Una pratica comune nelle applicazioni Web consiste nell'utilizzare il client (browser Web) come cache leggera. I cookie sono un'implementazione di questa pratica. Un cookie è in genere alcuni dati aggiunti dal server a una risposta HTTP tramite le sue intestazioni. È gestito dal browser che successivamente lo rimanda al server quando emette richieste, anche tramite intestazioni HTTP. I dati contenuti in un cookie possono essere utilizzati per emulare ciò che viene chiamato stato, l'illusione che il server mantenga una connessione in corso con il client. Solo, in questo caso, invece di un filo per mantenere "attiva" la connessione, è sufficiente avere istantanee dello stato dell'applicazione dopo che ha gestito la richiesta di un client. Queste istantanee vengono eseguite avanti e indietro tra client e server. Alla ricezione di una richiesta, il server legge prima il contenuto del cookie per ristabilire il contesto della sua conversazione con il client. Gestisce quindi la richiesta all'interno di quel contesto e prima di restituire la risposta al client, aggiorna il cookie. L'illusione di una sessione in corso viene quindi mantenuta.

Che aspetto ha un cookie?

Un tipico cookie sarebbe simile al seguente:

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

I cookie sono banali da esaminare da qualsiasi browser moderno. Su Firefox, ad esempio, vai su Preferenze> Privacy> Cronologia> rimuovi singoli cookie .

Il contentcampo è il più rilevante per l'applicazione. Altri campi contengono principalmente meta istruzioni per specificare vari ambiti di influenza.

Perché usare i cookie?

La risposta breve è la prestazione. L'uso dei cookie riduce al minimo la necessità di cercare elementi in vari archivi di dati (cache di memoria, file, database, ecc.), Accelerando così le operazioni sul lato dell'applicazione del server. Tieni presente che maggiore è il cookie, maggiore è il carico utile sulla rete, quindi ciò che salvi nella ricerca del database sul server potresti perdere sulla rete. Valuta attentamente cosa includere nei cookie.

Perché i cookie dovrebbero essere firmati?

I cookie vengono utilizzati per conservare tutti i tipi di informazioni, alcune delle quali possono essere molto sensibili. Inoltre, per loro natura, non sono sicuri e richiedono che una serie di precauzioni ausiliarie siano considerate sicure in qualsiasi modo per entrambe le parti, client e server. La firma dei cookie affronta in modo specifico il problema con cui possono essere armeggiati nel tentativo di ingannare le applicazioni server. Esistono altre misure per mitigare altri tipi di vulnerabilità, ti incoraggio a leggere di più sui cookie.

Come si può manomettere un cookie?

I cookie risiedono sul client in forma di testo e possono essere modificati senza alcuno sforzo. Un cookie ricevuto dall'applicazione server potrebbe essere stato modificato per una serie di motivi, alcuni dei quali potrebbero non essere innocenti. Immagina un'applicazione web che mantiene le informazioni di autorizzazione dei suoi utenti sui cookie e concede privilegi basati su tali informazioni. Se il cookie non è a prova di armeggiare, chiunque potrebbe modificarlo per elevare il proprio stato da "ruolo = visitatore" a "ruolo = amministratore" e l'applicazione non sarebbe più saggia.

Perché è SECRET_KEYnecessario firmare i cookie?

La verifica dei cookie è leggermente diversa dalla verifica del codice sorgente come descritto in precedenza. Nel caso del codice sorgente, l'autore originale è il fiduciario e il proprietario dell'impronta digitale di riferimento (il checksum), che sarà tenuto pubblico. Quello di cui non ti fidi è il codice sorgente, ma ti fidi della firma pubblica. Quindi, per verificare la tua copia della fonte, vuoi semplicemente che l'hash calcolato corrisponda all'hash pubblico.

Nel caso di un cookie, tuttavia l'applicazione non tiene traccia della firma, ne tiene traccia SECRET_KEY. Il SECRET_KEYè l'impronta digitale di riferimento. I cookie viaggiano con una firma che dichiarano legittima. Legittimità qui significa che la firma è stata emessa dal proprietario del cookie, ovvero l'applicazione, e in questo caso è l'affermazione che non ti fidi e devi verificare la validità della firma. Per fare ciò devi includere un elemento nella firma che ti è noto solo, questo è il SECRET_KEY. Qualcuno può cambiare un cookie, ma poiché non hanno l'ingrediente segreto per calcolare correttamente una firma valida non possono falsificarlo. Come affermato un po 'prima questo tipo di impronte digitali, dove oltre al checksum si fornisce anche una chiave segreta,

Che dire delle sessioni?

Le sessioni nella loro implementazione classica sono cookie che portano solo un ID nel contentcampo, il session_id. Lo scopo delle sessioni è esattamente lo stesso dei cookie firmati, ovvero prevenire la manomissione dei cookie. Le sessioni classiche hanno tuttavia un approccio diverso. Alla ricezione di un cookie di sessione, il server utilizza l'ID per cercare i dati della sessione nella propria memoria locale, che potrebbe essere un database, un file o talvolta una cache in memoria. Il cookie di sessione è impostato in genere per scadere alla chiusura del browser. A causa della fase di ricerca dell'archiviazione locale, questa implementazione di sessioni comporta in genere un aumento delle prestazioni. I cookie firmati stanno diventando un'alternativa preferita ed è così che vengono implementate le sessioni di Flask. In altre parole, le sessioni Flask lo sonocookie firmati e per utilizzare i cookie firmati in Flask basta usare la sua SessionAPI.

Perché non crittografare anche i cookie?

A volte il contenuto dei cookie può essere crittografato prima di essere firmato . Questo viene fatto se vengono considerati troppo sensibili per essere visibili dal browser (la crittografia nasconde i contenuti). La semplice firma dei cookie, tuttavia, risponde a un'esigenza diversa, quella in cui vi è il desiderio di mantenere un certo grado di visibilità e fruibilità dei cookie sul browser, evitando al contempo che vengano intromessi.

Cosa succede se cambio il SECRET_KEY?

Modificando il messaggio SECRET_KEYstai invalidando tutti i cookie firmati con la chiave precedente. Quando l'applicazione riceve una richiesta con un cookie che è stato firmato con un precedente SECRET_KEY, proverà a calcolare la firma con il nuovo SECRET_KEYed entrambe le firme non corrisponderanno, questo cookie e tutti i suoi dati verranno rifiutati, sarà come se il browser si sta connettendo al server per la prima volta. Gli utenti verranno disconnessi e il loro vecchio cookie verrà dimenticato, insieme a tutto ciò che è memorizzato all'interno. Si noti che questo è diverso dal modo in cui viene gestito un cookie scaduto. Un cookie scaduto può avere il suo leasing esteso se la sua firma viene estratta. Una firma non valida implica semplicemente un cookie non valido.

Pertanto, a meno che non si desideri invalidare tutti i cookie firmati, provare a conservare SECRET_KEYlo stesso per periodi prolungati.

Cosa c'è di buono SECRET_KEY?

Una chiave segreta dovrebbe essere difficile da indovinare. La documentazione su Sessioni ha una buona ricetta per la generazione casuale di chiavi:

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

Copia la chiave e la incolli nel tuo file di configurazione come valore di SECRET_KEY.

A parte l'uso di una chiave che è stata generata casualmente, potresti usare un complesso assortimento di parole, numeri e simboli, magari disposti in una frase nota solo a te, codificata in forma di byte.

Evitare Non impostare il SECRET_KEYdirettamente con una funzione che genera una chiave diversa ogni volta che viene chiamato. Ad esempio, non farlo:

# this is not good
SECRET_KEY = random_key_generator()

Ogni volta che la tua applicazione viene riavviata, verrà assegnata una nuova chiave, invalidando così la precedente.

Invece, apri una shell interattiva in python e chiama la funzione per generare la chiave, quindi copiala e incollala nella configurazione.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.