10.12. CORS en CSRF

CORS en CSRF zijn de twee browserzijdige beschermingen die een cam aan het open internet nodig heeft, naast HTTPS en login. Elk kost een paar regels om in te stellen. De onderstaande secties definiëren de term en tonen de microdot-integratie.

10.12.1. Wat CORS doet

Cross-Origin Resource Sharing (CORS) is het browsermechanisme waarmee een server zich kan aanmelden om specifieke andere origins zijn responses te laten lezen. De standaard same-origin policy van de browser blokkeert dat lezen: JavaScript op https://example.com kan geen responses lezen van https://yard-cam.example.com, omdat een andere host als een andere origin telt. CORS is de serverzijdige manier om uitzonderingen te verlenen voor gekozen peers.

Als het dashboard vanaf de cam zelf wordt geserveerd, is elk verzoek same-origin en doet CORS niets. De configuratie is van belang wanneer het dashboard ergens anders staat – een publieke URL zoals https://app.example.com die praat met een cam op 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 is de lijst met origins die de responses van de cam mogen lezen. De origin van het dashboard en alleen de origin van het dashboard – niet * – zodat een externe site de responses van de cam niet per ongeluk kan lezen.

allow_credentials=True laat cross-origin-verzoeken de sessiecookie meesturen, wat het dashboard nodig heeft om ingelogd te blijven over een origin-grens heen.

max_age=86400 vertelt de browser dat hij het preflight-resultaat een dag lang mag cachen. Browsers vuren een extra OPTIONS-verzoek af vóór elke cross-origin-aanroep die andere methoden dan GET/HEAD/POST gebruikt of aangepaste headers verstuurt; max_age reduceert die overhead tot één preflight per dag per route.

10.12.2. Wat CSRF doet

Cross-Site Request Forgery (CSRF) is de aanval waarbij een kwaadaardige pagina de browser van de gebruiker een geauthenticeerd verzoek laat afvuren op een vertrouwde server. Zelfs met CORS op zijn plaats zal een verborgen <form> op evil.com die POST naar https://yard-cam.example.com/config de cam bereiken, en de browser zal de sessiecookie van de cam meesturen – cookies volgen de bestemmingshost, niet de origin van de pagina die het verzoek doet – zodat de cam de POST vrolijk verwerkt alsof het de eigenaar was.

CSRF-bescherming weigert die verzoeken. microdot.csrf.CSRF voegt middleware toe die bij elk statuswijzigend verzoek de Sec-Fetch-Site-header inspecteert en alles weigert dat niet als same-origin is gelabeld (of afkomstig is van een door CORS toegestane origin):

from microdot.csrf import CSRF

CSRF(app, cors=cors)

Door de cors-instantie mee te geven, kan de middleware de toegestane origin van het dashboard alsnog toelaten – de cam accepteert nog steeds dashboard-POSTs, ook al zijn ze cross-origin.

Sec-Fetch-Site wordt automatisch door moderne browsers ingesteld; de cam hoeft aan de clientzijde niets te doen. Voor oudere browsers die de header niet versturen, is de CORS-toegestaanlijst de fallback-controle.

10.12.3. Webhooks vrijstellen

Als de cam een webhook-endpoint nodig heeft om POSTs van een externe clouddienst te accepteren – bijvoorbeeld een callback van de archiefprovider – markeer de route dan met @csrf.exempt zodat de middleware hem doorlaat. De handler is verantwoordelijk voor het op een andere manier verifiëren van het verzoek – meestal een Hash-based Message Authentication Code (HMAC) over de payload, berekend met een geheim dat de cam en de derde partij delen, wat bewijst dat het verzoek afkomstig is van iemand die het geheim kende. De achtertuincam heeft niets van dat alles, maar de decorator is er wanneer je hem nodig hebt.

10.12.4. De vierregelige basis

Zodra HTTPS op zijn plaats is, is de aanbevolen stack voor elke aan het internet blootgestelde cam-deployment:

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)

Sessie en login eerder in het hoofdstuk, CORS en CSRF hier, HTTPS uit het vorige onderwerp. De vier onderdelen stapelen op elkaar en blijven uit de weg van elke route.

De cam kan nu veilig aan het open internet worden blootgesteld – HTTPS, login, CSRF, CORS.