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.