2011-09-29 13 views
40

Nel febbraio 2011, Rails è stato modificato in require the CSRF token for all non-GET richieste, anche quelle per un endpoint API. Capisco la spiegazione del motivo per cui questo è un cambiamento importante per le richieste del browser, ma quel post sul blog non offre alcun consiglio su come un'API dovrebbe gestire la modifica.Progettazione API Rails senza disabilitare la protezione CSRF

Non sono interessato a disabilitare la protezione CSRF per determinate azioni.

Come si suppone che le API gestiscano questa modifica? È l'aspettativa che un client API effettui una richiesta GET all'API per ottenere un token CSRF, quindi include quel token in ogni richiesta durante quella sessione?

Sembra che il token non cambi da un POST a un altro. È sicuro assumere che il token non cambierà per la durata della sessione?

Non mi piace la gestione degli errori extra quando la sessione scade, ma suppongo sia meglio che dover ottenere un token prima di ogni richiesta POST/PUT/DELETE.

risposta

4

Rails funziona con la convenzione 'secure by default'. Richiesta di cross-site o cross-session Il contraffattore richiede che un utente abbia un browser e un altro sito Web affidabile. Questo non è rilevante per le API, poiché non vengono eseguite nel browser e non mantengono alcuna sessione. Pertanto, è necessario disabilitare CSRF per le API.

Ovviamente, è necessario proteggere l'API richiedendo l'autenticazione HTTP o un token dell'API personalizzato implementato o una soluzione OAuth.

+2

La pagina I link non è d'accordo: "Alcune combinazioni di plug-in del browser e reindirizzamenti HTTP possono essere utilizzate per ingannare il browser dell'utente in richieste tra domini che includono intestazioni HTTP arbitrarie specificate dall'hacker. e le richieste API e ignorano la protezione CSRF integrata e attaccano con successo un'applicazione. " –

+9

"Questo non è rilevante per le API, poiché non vengono eseguite nel browser": a volte il browser * è * il client dell'API, ovvero, – antinome

+1

http://stackoverflow.com/questions/9362910/rails -warning-cant-verify-csrf-token-authenticity-per-json-devise-requests/10049965 # 10049965 – montrealmike

41

Vecchia domanda ma la sicurezza è abbastanza importante che ritengo meriti una risposta completa. Come discusso in questo question ci sono ancora alcuni rischi di CSRF anche con le API. Sì, i browser dovrebbero proteggerli di default, ma poiché non hai il controllo completo del browser e dei plug-in installati dall'utente, è comunque opportuno considerarlo una best practice per la protezione da CSRF nella tua API.

Il modo in cui l'ho visto a volte è di analizzare il meta tag CSRF dalla pagina HTML stessa. Non mi piace molto, perché non si adatta bene al modo in cui funzionano molte applicazioni per le pagine singole e le API e ritengo che il token CSRF debba essere inviato in ogni richiesta indipendentemente dal fatto che si tratti di HTML, JSON o XML.

Quindi suggerirei di passare un token CSRF come un cookie o un valore di intestazione tramite un filtro successivo per tutte le richieste. L'API può semplicemente inviarlo nuovamente come valore di intestazione di X-CSRF-Token che Rails già controlla.

Ecco come ho fatto con AngularJS:

# In my ApplicationController 
    after_filter :set_csrf_cookie 

    def set_csrf_cookie 
    if protect_against_forgery? 
     cookies['XSRF-TOKEN'] = form_authenticity_token 
    end 
    end 

AngularJS automatically looks for a cookie nome XSRF-TOKEN ma sentitevi liberi di chiamarlo tutto quello che vuoi per i vostri scopi. Quindi quando invii un POST/PUT/DELETE dovresti impostare la proprietà dell'header X-CSRF-Token che Rails cerca automaticamente.

Sfortunatamente, AngualrJS invia già il cookie XSRF-TOKEN in un valore di intestazione di X-XSRF-TOKEN. E 'facile ignorare il comportamento predefinito Rails' per accogliere questo ApplicationController come questo:

protected 

    def verified_request? 
    super || form_authenticity_token == request.headers['X-XSRF-TOKEN'] 
    end 

Per Rails 4.2 è dotato di un aiuto ora per la convalida CSRF che dovrebbe essere utilizzato.

protected 

    def verified_request? 
    super || valid_authenticity_token?(session, request.headers['X-XSRF-TOKEN']) 
    end 

Spero sia utile.

MODIFICA: in un discussion on this for a Rails pull-request Ho inviato la segnalazione che passare il token CSRF tramite l'API per l'accesso è una pratica particolarmente negativa (ad esempio, qualcuno potrebbe creare l'accesso di terze parti per il sito che utilizza le credenziali dell'utente invece dei token) . Quindi cavet emptor. Spetta a te decidere quanto sei preoccupato per la tua applicazione. In questo caso è comunque possibile utilizzare l'approccio sopra riportato, ma solo rinviare il cookie CSRF a un browser che ha già una sessione autenticata e non per ogni richiesta. Ciò impedirà l'invio di un accesso valido senza utilizzare il metatag CSRF.

+3

La modifica è fondamentale: il server deve SOLO impostare il cookie CSRF per gli utenti autenticati. – brookr

+0

Cosa suggeriresti per l'autenticazione allora? Solo moduli basati su auth con il token CSRF impostato nell'HTML come di consueto, e poi con API con CSRF basato su header o cookie? –

+0

L'impostazione di un cookie senza 'httponly' non sembra sicura. 'Httponly' non impedisce a JS di accedere al cookie CSRF? Verrebbero invece passati insieme alla richiesta se si utilizza il [credenziale di fetch: il parametro 'same-origin''] (https://github.com/github/fetch#sending-cookies) per esempio. E perché utilizzare un nome non convenzionale per il cookie? Se usi 'X-CSRF-Token' ActionDispatch lo controllerà automaticamente senza sovrascrittura di richiesta_risultata? necessario. Io raccomanderei: 'cookies [" X-CSRF-Token "] = {valore: form_authenticity_token, httponly: true}' –

Problemi correlati