2011-11-21 8 views
11

Sto progettando l'API per un gruppo di siti. I siti sono molto simili (un po 'come StackOverflow, SuperUser e ServerFault), e ha senso per loro avere un back-end condiviso. Quindi abbiamo deciso di provare ad avere una bella API REST come back-end e una serie di frontend molto simili ma diversi che consumano detta API. I frontend dovrebbero preferibilmente essere tutti statici, ma non è un requisito difficile se risulta impossibile essere borderline.Come si protegge un'API RESTful consumata da un browser dagli attacchi CSRF?

Sto lavorando alla progettazione di questa API ora e sono preoccupato per le implicazioni sulla sicurezza, in particolare CSRF. Dalle mie conoscenze di base sugli attacchi CSRF, sono costituiti da due componenti importanti:

  1. Essere in grado di denominare la risorsa e il corpo della richiesta.

  2. Trying l'utente/browser nell'utilizzo di auth ambientale (come le sessioni) per effettuare una richiesta a tale risorsa che sembra autenticata.

Molti degli approcci classici per correggere gli attacchi CSRF si basano sulla sessione. Dal momento che la mia API REST non esegue realmente le sessioni, entrambe prevengono molti vettori e praticamente tutti i modi per risolverli. Ad esempio, il doppio invio non ha senso perché non c'è nulla da raddoppiare.

Il mio approccio iniziale riguardava l'attacco alla parte 2 di un attacco CSRF. Se autenticherò tutte le richieste (ad esempio usando l'autenticazione di base HTTP), e il browser non conserva quelle credenziali memorizzate (ad esempio, alcuni JS hanno fatto la richiesta), solo il JS con le credenziali può fare la richiesta, e abbiamo finito . L'ovvio svantaggio è che l'app deve conoscere le credenziali dell'utente. L'altro svantaggio leggermente meno ovvio è che se voglio memorizzare le credenziali in modo sicuro sull'estremità dell'API, la verifica di una password dovrebbe richiedere una quantità di tempo fissa e non trascurabile. Se la verifica di una password richiede 100ms in modo sicuro, allora ogni altra richiesta richiederà almeno 100 ms + eps, e ci vorranno alcuni accorgimenti maliziosi per evitare che si sentano lenti. Potrei essere in grado di memorizzarlo nella cache (dal momento che le credenziali saranno sempre le stesse), e se sono molto attento potrei riuscire a farlo senza introdurre una vulnerabilità temporale, ma suona come un vespaio.

OAuth 2.0 sembra un po 'esagerato, ma suppongo che potrebbe essere la soluzione migliore, dopotutto finisco per non implementarla male. Suppongo che per ora potrei fare l'Auth di base HTTP e passare a OAuth quando avremo sviluppatori di app di terze parti.

C'è un po 'di disadattamento di impedenza con OAuth. OAuth vuole davvero aiutare le app ad accedere ad altre app, in pratica. Voglio che gli utenti si registrino su uno dei frontend, prima che un account di questo tipo esista.

Ho anche considerato il punto di attacco 1 rendendo gli URL randomizzati, ovvero aggiungendo token a una stringa di query. Questo funzionerebbe sicuramente ed è molto vicino a come funziona il tradizionale token randomizzato in una forma, e dato HATEOAS dovrebbe essere abbastanza RESTful, anche se questo solleva due domande: 1) da dove inizi? Esiste un punto di inizio API obbligatorio in cui effettuare l'accesso utilizzando l'autenticazione di base HTTP? 2) Quanto conterebbe gli sviluppatori di app se loro non possono prevedere un URL in anticipo, HATEOAS essere dannato?

Ho visto How to prevent CSRF in a RESTful application?, ma non sono d'accordo con la premessa che gli URI randomizzati sono necessariamente irrilevanti. Inoltre, questa domanda non ha alcuna risposta soddisfacente e non menziona OAuth. Inoltre, la soluzione di invio doppio di sessione non è valida, come ho menzionato sopra (dominio diverso per il frontend statico rispetto all'endpoint API).

Mi rendo conto che ciò che sto fondamentalmente cercando di fare qui è cercare di consentire le richieste cross-site da un dominio e non consentirne l'altro, e non è facile. Sicuramente ci deve essere una soluzione ragionevole?

+0

Il problema, come dici tu, è che vuoi sia prevenire che consentire le richieste cross-site. Chiedi a Schrödinger. –

+0

Ciò non significa che non ci siano modi per risolvere il problema. Ne ho persino fornito uno che sarebbe, anche se un po 'lentamente. – lvh

risposta

0

La risposta dipende da cosa è necessario supportare. Se supponiamo di voler supportare un'applicazione web che utilizza il servizio REST e utilizzare lo stesso servizio REST per un'API che è qualcosa di diverso da un'app Web che sembra essere RESTFUL (potresti decidere che "sessioni"). sono per te!).

Per ora (/ me è piuttosto stanco) Penso che il modo in cui hai suggerito di utilizzare javascript con HTTP Basic Auth sia un buon inizio.

+0

L'autenticazione di base HTTP è vulnerabile a CSRF. – rook

+0

Potrebbe importare di elaborare? Mi rendo conto che i browser nascondono l'autenticazione di base HTTP, ma non chiediamo al browser di farlo; stiamo suggerendo di fare in modo che JS generi l'intestazione di autenticazione di base HTTP. Quindi le credenziali non finiscono mai nel pool di autenticazione dell'ambiente del browser e il sistema diventa immune da CSRF. Corretta? – lvh

3

Un token CSRF è per definizione "per stato utente" e pertanto non RESTful. La maggior parte delle API rompono i loro requisiti "per stato utente" ai fini della sicurezza e richiedono un token CSRF passato come parametro di intestazione HTTP.

Esistono altri modi per preventing CSRF. Il controllo del referente non è forte come un token CSRF, ma è RESTful e il valore di MOLTO è improbabile che venga compromesso. Tieni presente che la mancanza di un referente deve essere considerata una richiesta non riuscita.

XSS può essere utilizzato per bypassare la prevenzione CSRF basata su token e la prevenzione CSRF basata su referer.

+0

Stessa osservazione come nella mia risposta al tuo commento. Puoi approfondire perché l'autenticazione di base HTTP non previene CSRF quando aggiungi l'intestazione di autenticazione usando JS? Inoltre, in che modo OAuth non impedisce CSRF? L'unica volta che parte di OAuth lo garantisce? – lvh

+0

@lvh un nome utente e una password sono stati per utente inviati con la richiesta. Un nonce crittografico utilizzato come token CSRF è anche per stato utente inviato con ogni richiesta, ma è più sicuro perché dovrebbe essere un valore dinamico legato a una sessione. Solitamente i protocolli RESTful si basano su un criptato crittografico statico o "api key", che è stato per utente e ferma anche CSRF. L'invio nell'intestazione HTTP non lo rende magicamente riposante, ma può aprire la porta per attaccare se altre richieste inviate da quel browser contengono questo valore. – rook

+0

Ma questo è il mio punto. Qual è il vettore di attacco se non diventa un'autenticazione del browser ambiente? Che si tratti di un nonce o delle credenziali effettive non ha importanza ai fini di CSRF: il browser non * sa *, quindi come potrebbe essere ingannato fornirlo? – lvh

0

Ho un'altra soluzione potenziale, quindi la sto elencando come risposta. Sentitevi liberi di smontarlo :)

auth.platform.com accetta l'autenticazione e imposta i cookie. Se auth.site.com è un CNAME per auth.platform.com, la richiesta a auth.site.com (che termina con auth.platform.com dopo la risoluzione) può impostare un cookie per site.com? In questo modo ho potuto inviare due volte i cookie di sessione.

Ovviamente, auth.platform.com imposterà solo i cookie per alcuni domini autorizzati.

MODIFICA: Tranne ovviamente questo non funzionerà affatto, perché dovresti usare HTTPS per fare l'autenticazione in modo sicuro, e HTTPS vedrà proprio attraverso il tuo inganno.

0

Progettare l'API come un vero RESTful, previene i vettori più comuni CSRF:

  • cookie evitando impedisce loro di essere "rubato",
  • utilizzando GET per le operazioni di "sicuri" impedisce img e iframes per attivare azioni non sicure senza l'interazione dell'utente.

Quindi è necessario implementare CORS per consentire ai browser degli utenti di bloccare le richieste da origini non affidabili.

+1

-1 Nessuno di questi ha a che fare con CSRF, ad eccezione del commento su CORS. CORS è pericoloso e può essere utilizzato per leggere un token CSRF o altre informazioni sensibili. CORS non può essere usato per prevenire CSRF. – rook

Problemi correlati