10.12. CORS e CSRF¶
CORS e CSRF sono le due protezioni lato browser di cui una camera esposta su internet ha bisogno, insieme a HTTPS e login. Ciascuna richiede poche righe per essere configurata. Le sezioni seguenti definiscono il termine e mostrano l’integrazione con microdot.
10.12.1. Cosa fa CORS¶
Il Cross-Origin Resource Sharing (CORS) è il meccanismo del browser che consente a un server di scegliere esplicitamente di permettere ad altre origini specifiche di leggere le sue risposte. La same-origin policy predefinita del browser blocca questa lettura: il JavaScript su https://example.com non può leggere le risposte da https://yard-cam.example.com, perché un host diverso conta come origine diversa. Il CORS è il modo, lato server, di concedere eccezioni a peer scelti.
Se la dashboard viene servita dalla camera stessa, ogni richiesta è same-origin e il CORS non fa nulla. La configurazione conta quando la dashboard risiede altrove: un URL pubblico come https://app.example.com che comunica con una camera all’indirizzo https://yard-cam.example.com:
from microdot.cors import CORS
cors = CORS(
app,
allowed_origins=['https://app.example.com'],
allow_credentials=True,
max_age=86400,
)
allowed_origins è l’elenco delle origini autorizzate a leggere le risposte della camera. L’origine della dashboard e solo l’origine della dashboard – non * – così che un sito di terze parti non possa leggere per errore le risposte della camera.
allow_credentials=True consente alle richieste cross-origin di includere il cookie di sessione, che è ciò di cui la dashboard ha bisogno per restare autenticata oltre il confine tra le origini.
max_age=86400 indica al browser che può mettere in cache il risultato del preflight per un giorno. I browser inviano una richiesta OPTIONS aggiuntiva prima di qualsiasi chiamata cross-origin che usa metodi diversi da GET/HEAD/POST o che invia header personalizzati; max_age riduce questo overhead a un preflight al giorno per route.
10.12.2. Cosa fa CSRF¶
Il Cross-Site Request Forgery (CSRF) è l’attacco in cui una pagina malevola fa sì che il browser dell’utente invii una richiesta autenticata a un server fidato. Anche con il CORS attivo, un <form> nascosto su evil.com che fa POST verso https://yard-cam.example.com/config raggiungerà la camera, e il browser allegherà il cookie di sessione della camera – i cookie seguono l’host di destinazione, non l’origine della pagina che effettua la richiesta – perciò la camera elaborerà tranquillamente il POST come se provenisse dal proprietario.
La protezione CSRF rifiuta tali richieste. microdot.csrf.CSRF aggiunge un middleware che ispeziona l’header Sec-Fetch-Site su ogni richiesta che modifica lo stato e rifiuta tutto ciò che non è etichettato come same-origin (o che proviene da un’origine consentita dal CORS):
from microdot.csrf import CSRF
CSRF(app, cors=cors)
Passare l’istanza cors consente al middleware di ammettere automaticamente l’origine consentita della dashboard: la camera accetta comunque i POST della dashboard anche se sono cross-origin.
Sec-Fetch-Site viene impostato automaticamente dai browser moderni; la camera non deve fare nulla sul lato client. Per i browser più vecchi che non inviano questo header, l’elenco di origini consentite dal CORS funge da controllo di riserva.
10.12.3. Esenzione dei webhook¶
Se la camera necessita di un endpoint webhook per accettare POST da un servizio cloud di terze parti – ad esempio una callback dal fornitore dell’archivio – contrassegna la route con @csrf.exempt in modo che il middleware la lasci passare. L’handler è responsabile di verificare la richiesta in qualche altro modo, di solito tramite un Hash-based Message Authentication Code (HMAC) calcolato sul payload con un segreto condiviso tra la camera e la terza parte, che dimostra che la richiesta proviene da qualcuno che conosceva il segreto. La camera del cortile non ha nulla di tutto ciò, ma il decoratore è disponibile quando ne hai bisogno.
10.12.4. La base di quattro righe¶
Una volta che HTTPS è attivo, lo stack consigliato per qualsiasi distribuzione di una camera esposta su internet è:
Session(app, secret_key=SECRET,
cookie_options={'http_only': True, 'secure': True})
login = Login()
cors = CORS(app, allowed_origins=[...], allow_credentials=True)
CSRF(app, cors=cors)
Sessione e login più indietro nel capitolo, CORS e CSRF qui, HTTPS dall’argomento precedente. I quattro elementi si sovrappongono l’uno all’altro e non interferiscono con il funzionamento di nessuna route.
La camera è ora sicura per essere esposta su internet: HTTPS, login, CSRF, CORS.