microdot.csrf — protezione CSRF

Rifiuta le richieste che modificano lo stato e che hanno origine cross-site. Il controllo viene eseguito come hook before_request e utilizza l’header Sec-Fetch-Site fornito dal browser (con l’header Origin come fallback per i browser più vecchi, quando abbinato a un’istanza microdot.cors.CORS).

class CSRF

class microdot.csrf.CSRF(app: Microdot | None = None, cors=None, protect_all: bool = True, allow_subdomains: bool = False)
app

L’istanza microdot.Microdot su cui installarsi. Opzionale; chiama initialize() in seguito se non fornita.

cors

L’istanza microdot.cors.CORS che definisce le origini attendibili dell’applicazione. Necessaria per il fallback all’header Origin sui browser che non inviano Sec-Fetch-Site. Opzionale; senza di essa si applica solo il controllo Sec-Fetch-Site.

protect_all

Se True (predefinito), ogni route tranne GET, HEAD e OPTIONS è protetta automaticamente. Le route possono essere esentate individualmente con exempt(). Se False, nessuna route è protetta per impostazione predefinita e le singole route aderiscono con protect().

allow_subdomains

Se True, le richieste provenienti dai sottodomini delle origini dell’applicazione vengono accettate (Sec-Fetch-Site same-site, oppure suffisso di origine corrispondente).

initialize(app: Microdot, cors=None)

Si collega a app se la costruzione è stata posticipata.

exempt(f)

Decoratore che esenta una route dalla protezione CSRF. Posizionalo direttamente dopo il decoratore della route:

@app.post('/webhook')
@csrf.exempt
async def webhook(request):
    # accepts cross-site POSTs
protect(f)

Decoratore che forza la protezione CSRF su una route che altrimenti sarebbe esente (ad es. una route GET oppure ogni route quando protect_all=False).

SAFE_METHODS: list

Attributo di classe che elenca i metodi non protetti per impostazione predefinita – ['GET', 'HEAD', 'OPTIONS'].

Esempio:

from microdot import Microdot
from microdot.cors import CORS
from microdot.csrf import CSRF

app = Microdot()
cors = CORS(app, allowed_origins=['https://app.example.com'])
csrf = CSRF(app, cors=cors)

@app.post('/api/save')
async def save(request):
    # automatically CSRF-protected
    return {'ok': True}

Una richiesta è consentita quando Sec-Fetch-Site riporta same-origin o none (oppure same-site quando allow_subdomains=True). Se l’header è assente, l”Origin della richiesta viene confrontato con l’allow-list CORS. Le richieste prive di entrambi gli header vengono accettate (tipico per le chiamate API dirette non soggette al CSRF del browser).