Domanda demystify Flask app.secret_key


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

Questo è tutto ciò che il guida per l'utente di flacone ha da dire a questo proposito.

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

  • Perché Flask ci obbliga a impostare questo secret_key proprietà?
  • Come Flask usa il secret_key proprietà?

60
2018-03-17 19:47


origine


risposte:


Tutto ciò che richiede la crittografia (per la sicurezza contro la manomissione da parte di aggressori) richiede la chiave segreta da impostare. Per appena Flask stesso, che "qualsiasi cosa" è il Session oggetto, ma altre estensioni possono utilizzare lo stesso segreto.

secret_key è semplicemente il valore impostato per SECRET_KEY chiave di configurazione, oppure puoi impostarla direttamente.

Il Sezione Sessioni in Avvio rapido ha buoni, saggi consigli su quale tipo di segreto sul lato server dovresti impostare.

La crittografia si basa sui segreti; se non si imposta un segreto sul lato server per la crittografia da utilizzare, tutti sarebbero in grado di interrompere la crittografia; è 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 a algoritmo di hashing crittografico; solo se hai lo stesso identico segreto e i dati originali possono ricreare questo valore, lasciando che Flask rilevi se qualcosa è stato alterato senza permesso. Poiché il segreto non viene mai incluso con i dati Flask invia al client, un client non può manomettere i dati della sessione e sperare di produrre una nuova firma valida.

Flask usa il itsdangerous biblioteca fare tutto il duro lavoro; le sessioni usano il itsdangerous.URLSafeTimedSerializer classe con un serializzatore JSON personalizzato.


59
2018-03-17 19:49



La risposta qui sotto riguarda principalmente Biscotti firmati, un'implementazione del concetto di sessioni (come usato nelle applicazioni web). Flask offre sia cookie normali (non firmati) (via request.cookies e response.set_cookie()) e cookie firmati (via flask.session). La risposta ha due parti, la prima descrive come viene generato un cookie firmato e il secondo è presentato sotto forma di un controllo di qualità che affronta diversi aspetti dello schema. La sintassi utilizzata per gli esempi è Python3, ma i concetti si applicano anche alle versioni precedenti.

Cosa è 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, il SECRET_KEY è usato in un modo simile a come un "sale" sarebbe usato per confondere una password prima di cancellarla. Ecco una descrizione (selvaggiamente) semplificata del concetto. Il codice negli esempi è pensato per essere illustrativo. Molti passaggi sono stati omessi e non tutte le funzioni esistono effettivamente. L'obiettivo qui è quello di fornire una comprensione dell'idea generale, le implementazioni reali saranno un po 'più coinvolte. Inoltre, tieni presente che Flask fa la maggior parte di questo per te in background. Quindi, oltre ad impostare i valori sul tuo cookie (tramite l'API di sessione) e fornendo a SECRET_KEY, non è solo sconsigliato implementarlo di nuovo, ma non c'è bisogno di farlo:

Firma del biscotto di un povero

Prima di inviare una risposta al browser:

(1) Primo a 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) creare 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) il SECRET_KEY alla stringa 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 content campo 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 --> 

Dopo aver ricevuto il cookie dal browser:

(5) Quando il browser restituisce questo cookie al server, rimuovere la firma dai cookie content campo per recuperare 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) Usa il cookie originale con quello dell'applicazione SECRET_KEY ricalcolare la firma usando lo stesso metodo del punto 3.

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

(7) Confrontare il risultato calcolato con la firma precedentemente estratta dal cookie appena ricevuto. Se corrispondono, sappiamo che il cookie non è stato incasinato. 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, è possibile rispondere con un numero qualsiasi di azioni, registrare l'evento, eliminare il cookie, emetterne uno nuovo, reindirizzare a una pagina di accesso, ecc.

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

HMAC (Message Authentication Code) basato su hash

Il tipo di firma generato sopra che richiede una chiave segreta per garantire che l'integrità di alcuni contenuti sia chiamata in crittografia a Codice di autenticazione del messaggio o MAC.

Ho specificato in precedenza che l'esempio sopra riportato è una semplificazione eccessiva di tale concetto e che non era una buona idea implementare la propria firma. Questo perché viene chiamato l'algoritmo utilizzato per firmare i cookie in Flask HMAC ed è un po 'più coinvolto rispetto alla semplice procedura di cui sopra. L'idea generale è la stessa, ma a causa di ragioni che vanno oltre lo 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 è il caso, 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()

Il documento per hmac e hashlib.


La "demistificazione" di SECRET_KEY :)

Che cosa è una "firma" in questo contesto?

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

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

Diciamo per esempio che stai per scaricare la fonte di un progetto in un file gzip 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 gli stessi, sai che hai una copia identica.

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 avere una migliore comprensione di come e perché SECRET_KEY è utile. Ti incoraggio fortemente a seguire 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. Viene mantenuto dal browser che lo invia di nuovo al server durante l'emissione delle richieste, anche tramite le intestazioni http. I dati contenuti in un cookie possono essere utilizzati per emulare ciò che viene chiamato statefulness, l'illusione che il server stia mantenendo una connessione continua con il client. Solo, in questo caso, invece di un filo per mantenere "viva" la connessione, è sufficiente disporre di istantanee dello stato dell'applicazione dopo che ha gestito la richiesta di un client. Queste istantanee vengono spostate avanti e indietro tra client e server. Dopo aver ricevuto una richiesta, il server prima legge il contenuto del cookie per ristabilire il contesto della sua conversazione con il cliente. Quindi gestisce la richiesta in quel contesto e prima di restituire la risposta al client, aggiorna il cookie. Viene così mantenuta l'illusione di una sessione in corso.

Che aspetto ha un cookie?

Un tipico cookie sarebbe simile a questo:

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 leggere da qualsiasi browser moderno. Ad esempio su Firefox vai a Preferenze> Privacy> Cronologia> rimuovi i singoli cookie.

Il content il campo è il più pertinente per l'applicazione. Altri campi contengono per lo più meta istruzioni per specificare vari ambiti di influenza.

Perché usare i cookie?

La risposta breve è la prestazione. L'uso dei cookie minimizza la necessità di cercare le cose in vari archivi di dati (cache di memoria, file, database, ecc.), Accelerando così le cose dal lato delle applicazioni del server. Tieni presente che più grande è il cookie, più pesante è il carico utile sulla rete, quindi cosa si salva nella ricerca di database sul server che si potrebbe perdere sulla rete. Valuta attentamente cosa includere nei tuoi cookie.

Perché i cookie devono essere firmati?

I cookie sono utilizzati per conservare ogni tipo di informazione, alcuni dei quali possono essere molto sensibili. Sono anche per loro natura non sicuri e richiedono l'adozione di una serie di precauzioni ausiliarie per essere 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 messi a tacere nel tentativo di ingannare le applicazioni server. Esistono altre misure per mitigare altri tipi di vulnerabilità, vi incoraggio a leggere di più sui cookie.

Come può essere manomesso un cookie?

I cookie risiedono sul client in forma di testo e possono essere modificati senza 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 sui suoi utenti sui cookie e concede i privilegi in base a tali informazioni. Se il cookie non è a prova di intasamento, chiunque potrebbe modificarne le caratteristiche per elevarne lo stato da "role = visitor" a "role = admin" e l'applicazione non sarebbe più saggia.

Perché è un SECRET_KEY necessario firmare i cookie?

La verifica dei cookie è un po '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. Ciò di cui non ti fidi è il codice sorgente, ma ti fidi della firma pubblica. Quindi per verificare la tua copia della fonte devi 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 affermano essere legittimi. Legittimità qui significa che la firma è stata emessa dal proprietario del cookie, cioè l'applicazione, e in questo caso è tale affermazione che non ti fidi e devi verificare la validità della firma. Per fare ciò è necessario includere un elemento nella firma che è noto solo a te, questo è il SECRET_KEY. Qualcuno può cambiare un cookie, ma dal momento che non hanno l'ingrediente segreto per calcolare correttamente una firma valida, non possono spoofarla. Come affermato un po 'prima, questo tipo di fingerprinting, in cui oltre al checksum si fornisce anche una chiave segreta, è chiamato un codice di autenticazione dei messaggi.

Che dire delle sessioni?

Le sessioni nella loro implementazione classica sono i cookie che portano solo un ID nel file content campo, il session_id. Lo scopo delle sessioni è esattamente lo stesso dei cookie firmati, ad esempio per impedire la manomissione dei cookie. Le sessioni classiche hanno un approccio diverso però. Dopo aver ricevuto 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 viene in genere impostato per scadere quando il browser viene chiuso. A causa del passaggio di ricerca dell'archiviazione locale, questa implementazione delle sessioni comporta in genere un impatto sulle prestazioni. I cookie firmati stanno diventando un'alternativa preferita ed è così che vengono implementate le sessioni di Flask. In altre parole, sessioni Flask siamo cookie firmati e per usare i cookie firmati in Flask basta usarne uno Session API.

Perché non criptare anche i cookie?

A volte il contenuto dei cookie può essere crittografato prima anche essere firmato. Questo viene fatto se sono considerati troppo sensibili per essere visibili dal browser (la crittografia nasconde il contenuto). La semplice firma dei cookie, tuttavia, risponde a una necessità diversa, quella in cui si desidera mantenere un certo grado di visibilità e usabilità dei cookie sul browser, evitando che vengano coinvolti.

Cosa succede se cambio il SECRET_KEY?

Cambiando il SECRET_KEY stai invalidando tutti 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_KEYe entrambe le firme non corrisponderanno, questo cookie e tutti i relativi dati verranno rifiutati, sarà come se il browser si collegasse al server per la prima volta. Gli utenti verranno disconnessi e il loro vecchio cookie dimenticato insieme a qualsiasi cosa memorizzata all'interno. Si noti che questo è diverso dal modo in cui viene gestito un cookie scaduto. Un cookie scaduto può avere il suo lease esteso se la sua firma viene verificata. Una firma non valida implica semplicemente un semplice cookie non valido.

Quindi, se non si desidera invalidare tutti i cookie firmati, provare a mantenere il SECRET_KEY lo stesso per periodi prolungati.

Cosa va bene SECRET_KEY?

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

>>> 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 file di configurazione come valore di SECRET_KEY.

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

Fare non impostare il SECRET_KEY direttamente con una funzione che genera una chiave diversa ogni volta che viene chiamata. 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.

Aprire invece una shell python interattiva e chiamare la funzione per generare la chiave, quindi copiarla e incollarla nella configurazione.


21
2018-02-03 11:29