Autenticazione RESTful


745

Cosa significa autenticazione RESTful e come funziona? Non riesco a trovare una buona panoramica su Google. La mia unica comprensione è che passi la chiave di sessione (remeberal) nell'URL, ma questo potrebbe essere terribilmente sbagliato.


3
Quando google Autenticazione Restful trovo una dozzina di plugin RoR. Suppongo che NON siano quello che stai cercando. Se non RoR, allora quale lingua? Quale web server?
S. Lott,

2
Non sarà terribilmente sbagliato se si utilizza HTTPS. La richiesta HTTP completa insieme all'URL verrebbe crittografata.
Bharat Khatri,

4
@BharatKhatri: Sì, lo sarebbe. Non trasmetterei mai informazioni sensibili nell'URL visibili all'utente. È molto più probabile che queste informazioni perdano per scopi pratici. HTTPS non può essere d'aiuto per perdite accidentali.
Jo So,

2
@jcoffland: cosa intendi per autenticazione RESTful reale? Sono interessato perché ho appena implementato la terza via dalla risposta accettata, tuttavia non ne sono soddisfatto (non mi piace il parametro aggiuntivo nell'URL).
BlueLettuce16,

4
alcune persone usano jwt.io/introduction per risolvere questo problema. Faccio ricerche su questo proprio ora per risolvere il mio caso: stackoverflow.com/questions/36974163/… >> Speriamo che funzioni bene.
toha

Risposte:


586

Come gestire l'autenticazione in un'architettura Client-Server RESTful è una questione di dibattito.

Comunemente, può essere raggiunto, nel mondo SOA su HTTP tramite:

  • Autenticazione HTTP di base su HTTPS;
  • Cookie e gestione delle sessioni;
  • Token nelle intestazioni HTTP (ad es. OAuth 2.0 + JWT);
  • Autenticazione della query con parametri di firma aggiuntivi.

Dovrai adattare, o ancor meglio mescolare quelle tecniche, per abbinare al meglio la tua architettura software.

Ogni schema di autenticazione ha i propri PRO e CON, a seconda dello scopo della politica di sicurezza e dell'architettura software.

Autenticazione HTTP di base su HTTPS

Questa prima soluzione, basata sul protocollo HTTPS standard, è utilizzata dalla maggior parte dei servizi web.

GET /spec.html HTTP/1.1
Host: www.example.org
Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==

È facile da implementare, disponibile per impostazione predefinita su tutti i browser, ma presenta alcuni inconvenienti noti, come la terribile finestra di autenticazione visualizzata sul browser, che persisterà (non esiste una funzione simile a LogOut qui), un consumo aggiuntivo di CPU sul lato server, e il fatto che il nome utente e la password siano trasmessi (tramite HTTPS) al Server (dovrebbe essere più sicuro lasciare che la password rimanga solo sul lato client, durante l'immissione da tastiera, e sia memorizzata come hash sicuro sul Server) .

Potremmo utilizzare l' autenticazione Digest , ma richiede anche HTTPS, poiché è vulnerabile agli attacchi MiM o Replay ed è specifico per HTTP.

Sessione tramite cookie

Ad essere onesti, una sessione gestita sul Server non è veramente Stateless.

Una possibilità potrebbe essere quella di conservare tutti i dati all'interno del contenuto dei cookie. E, in base alla progettazione, il cookie viene gestito sul lato server (il client, infatti, non tenta nemmeno di interpretare questi dati sui cookie: li restituisce al server solo ad ogni richiesta successiva). Ma questi dati sui cookie sono dati sullo stato dell'applicazione, quindi il client dovrebbe gestirli, non il server, in un puro mondo Stateless.

GET /spec.html HTTP/1.1
Host: www.example.org
Cookie: theme=light; sessionToken=abc123

La stessa tecnica dei cookie è collegata a HTTP, quindi non è veramente RESTful, che dovrebbe essere indipendente dal protocollo, IMHO. È vulnerabile agli attacchi MiM o Replay .

Concesso tramite token (OAuth2)

Un'alternativa è inserire un token nelle intestazioni HTTP in modo che la richiesta sia autenticata. Questo è ciò che fa OAuth 2.0, ad esempio. Vedi RFC 6749 :

 GET /resource/1 HTTP/1.1
 Host: example.com
 Authorization: Bearer mF_9.B5f-4.1JqM

In breve, questo è molto simile a un cookie e presenta gli stessi problemi: non apolidi, basandosi sui dettagli di trasmissione HTTP e soggetti a molte debolezze di sicurezza - tra cui MiM e Replay - quindi deve essere utilizzato solo su HTTPS. In genere, un JWT viene utilizzato come token.

Autenticazione query

L'autenticazione della query consiste nel firmare ogni richiesta RESTful tramite alcuni parametri aggiuntivi sull'URI. Vedi questo articolo di riferimento .

È stato definito come tale in questo articolo:

Tutte le query REST devono essere autenticate firmando i parametri della query ordinati in minuscolo, in ordine alfabetico utilizzando la credenziale privata come token di firma. La firma dovrebbe avvenire prima dell'URL che codifica la stringa di query.

Questa tecnica è forse la più compatibile con un'architettura Stateless e può anche essere implementata con una gestione delle sessioni leggere (utilizzando sessioni in memoria invece della persistenza del DB).

Ad esempio, ecco un esempio di URI generico dal link sopra:

GET /object?apiKey=Qwerty2010

dovrebbe essere trasmesso come tale:

GET /object?timestamp=1261496500&apiKey=Qwerty2010&signature=abcdef0123456789

La stringa che viene firmata è /object?apikey=Qwerty2010&timestamp=1261496500e la firma è l'hash SHA256 di quella stringa utilizzando il componente privato della chiave API.

La memorizzazione nella cache dei dati lato server può essere sempre disponibile. Ad esempio, nel nostro framework, memorizziamo nella cache le risposte a livello di SQL, non a livello di URI. Quindi l'aggiunta di questo parametro extra non rompe il meccanismo della cache.

Vedi questo articolo per alcuni dettagli sull'autenticazione RESTful nel nostro framework client / server ORM / SOA / MVC, basato su JSON e REST. Poiché consentiamo la comunicazione non solo su HTTP / 1.1, ma anche su pipe o messaggi GDI (localmente), abbiamo cercato di implementare un modello di autenticazione RESTful e non fare affidamento sulla specificità HTTP (come intestazione o cookie).

Nota successiva : l'aggiunta di una firma nell'URI può essere vista come una cattiva pratica (poiché ad esempio verrà visualizzata nei registri del server http), quindi deve essere mitigata, ad esempio da un TTL appropriato per evitare replay. Ma se i tuoi registri http sono compromessi, avrai sicuramente maggiori problemi di sicurezza.

In pratica, la prossima autenticazione di token MAC per OAuth 2.0 potrebbe essere un enorme miglioramento rispetto allo schema attuale "Concesso da token". Ma questo è ancora un lavoro in corso ed è legato alla trasmissione HTTP.

Conclusione

Vale la pena concludere che REST non è solo basato su HTTP, anche se, in pratica, è anche principalmente implementato su HTTP. REST può usare altri livelli di comunicazione. Quindi un'autenticazione RESTful non è solo un sinonimo di autenticazione HTTP, qualunque sia la risposta di Google. Non dovrebbe nemmeno usare affatto il meccanismo HTTP ma deve essere estratto dal livello di comunicazione. E se usi la comunicazione HTTP, grazie all'iniziativa Let's Encrypt non c'è motivo di non utilizzare il corretto HTTPS, necessario in aggiunta a qualsiasi schema di autenticazione.


5
Se lo usi Cookiecome un sostituto migliore per HTTP Basic Authte puoi fare autenticazione davvero senza stato con un metodo per scadere l'autenticazione e la possibilità di disconnettersi. Un'implementazione di esempio potrebbe utilizzare un cookie chiamato Emulated-HTTP-Basic-Authcon un valore simile all'autent di base HTTP reale e inoltre impostare la scadenza. La disconnessione può quindi essere implementata rimuovendo quel cookie. Immagino che qualsiasi client in grado di supportare HTTP Basic Auth possa supportare anche l'autenticazione dei cookie in questo modo.
Mikko Rantalainen il

4
@MikkoRantalainen Ma questo cookie sarà comunque gestito dal server, come ho scritto. È una specie di apolide, ma non "puro" apolide. In ogni caso, è necessario un codice JavaScript dedicato all'accesso / disconnessione del client, il che è perfettamente possibile, ad es. Con HTTP Digest Auth : una buona idea, ma qui non è un grande vantaggio reinventare la ruota.
Arnaud Bouchez,

4
Direi che il server implementa l'interfaccia utente e la logica per la configurazione dell'intestazione, ma l'intestazione stessa è senza stato. Un client progettato per l'API potrebbe saltare utilizzando la guida del server per configurare l'intestazione e passare semplicemente le informazioni richieste simili a HTTP Basic Auth. Il mio punto è che i comuni UA (browser) hanno un'implementazione così scarsa di Basic Auth che non può essere utilizzata. In Cookiealternativa, è possibile utilizzare un'emulazione fornita dallo stesso server per le stesse cose in un'altra intestazione ( ).
Mikko Rantalainen,

6
Immagino che la risposta corretta sia stackoverflow.com/questions/6068113/…
graffic

7
La brutta password richiesta per l'autorizzazione HTTP apparirà solo se il server lo richiede inviando la risposta 401 non autorizzata. Se non ti piace, basta inviare un 403 proibito. La pagina di errore può includere un metodo per accedere o un collegamento ad esso. Tuttavia, ma l'argomento principale contro i cookie E l'autenticazione http (indipendentemente dal fatto che lo stato sia lato server o lato client) è che siano vulnerabili alla falsificazione di richieste tra siti. Per questo motivo, l'approccio migliore è uno schema di autorizzazione personalizzato, un'intestazione di autorizzazione personalizzata o un parametro GET o POST personalizzato.
Dobes Vandermeer,

418

Dubito che le persone che gridano con entusiasmo "Autenticazione HTTP" abbiano mai provato a creare un'applicazione basata su browser (anziché un servizio web da macchina a macchina) con REST (nessuna offesa intesa - non credo che abbiano mai affrontato le complicazioni) .

I problemi che ho riscontrato con l'utilizzo dell'autenticazione HTTP su servizi RESTful che producono pagine HTML da visualizzare in un browser sono:

  • l'utente riceve in genere una brutta casella di accesso creata dal browser, che è molto ostile per l'utente. non è possibile aggiungere recupero password, caselle di aiuto, eccetera.
  • disconnettersi o accedere con un nome diverso è un problema: i browser continueranno a inviare informazioni di autenticazione al sito fino alla chiusura della finestra
  • i timeout sono difficili

Un articolo molto approfondito che affronta questi punti per punto è qui , ma questo si traduce in un sacco di hacker javascript specifici del browser, soluzioni alternative per soluzioni alternative, eccetera. In quanto tale, inoltre, non è compatibile con le versioni successive, pertanto richiederà una manutenzione costante poiché vengono rilasciati nuovi browser. Non considero quel design pulito e chiaro, inoltre sento che c'è molto lavoro extra e mal di testa solo per poter mostrare con entusiasmo il mio badge REST ai miei amici.

Credo che i cookie siano la soluzione. Ma aspetta, i biscotti sono cattivi, vero? No, non lo sono, il modo in cui i cookie vengono spesso utilizzati è malvagio. Un cookie stesso è solo una parte delle informazioni sul lato client, proprio come le informazioni di autenticazione HTTP che il browser terrà traccia durante la navigazione. E questa informazione sul lato client viene inviata al server ad ogni richiesta, proprio come le informazioni di autenticazione HTTP. Concettualmente, l'unica differenza è che il contenuto di questo stato del lato client può essere determinato dal server come parte della sua risposta.

Rendendo le sessioni una risorsa RESTful con solo le seguenti regole:

  • Una sessione associa una chiave a un ID utente (e possibilmente un timestamp last-action per i timeout)
  • Se esiste una sessione , significa che la chiave è valida.
  • Accesso significa POSTARE / sessioni, una nuova chiave è impostata come cookie
  • Logout significa ELIMINAZIONE / sessioni / {chiave} (con il POST sovraccarico, ricorda, siamo un browser e HTML 5 è ancora una lunga strada da percorrere)
  • L'autenticazione viene effettuata inviando la chiave come cookie ad ogni richiesta e verificando se la sessione esiste e è valida

L'unica differenza rispetto all'autenticazione HTTP, ora, è che la chiave di autenticazione viene generata dal server e inviata al client che continua a rispedirla, anziché al client che la calcola dalle credenziali immesse.

converter42 aggiunge che quando si utilizza https (cosa che dovremmo), è importante che il cookie abbia il suo flag di sicurezza impostato in modo che le informazioni di autenticazione non vengano mai inviate su una connessione non sicura. Ottimo punto, non l'avevo visto da solo.

Sento che questa è una soluzione sufficiente che funziona bene, ma devo ammettere che non sono abbastanza esperto di sicurezza per identificare potenziali buchi in questo schema - tutto quello che so è che centinaia di applicazioni Web non RESTful usano essenzialmente lo stesso protocollo di accesso ($ _SESSION in PHP, HttpSession in Java EE, ecc.). Il contenuto dell'intestazione del cookie viene semplicemente utilizzato per indirizzare una risorsa lato server, proprio come una lingua di accettazione potrebbe essere utilizzata per accedere alle risorse di traduzione, eccetera. Sento che è lo stesso, ma forse altri no? Cosa ne pensate ragazzi?


68
Questa è una risposta pragmatica e la soluzione proposta funziona. Tuttavia, usare i termini "RESTful" e "session" nella stessa frase è semplicemente sbagliato (a meno che non ci sia anche "non" in mezzo;). In altre parole: qualsiasi servizio Web che utilizza sessioni NON è RESTful (per definizione). Non fraintendetemi: è ancora possibile utilizzare questa soluzione (YMMV), ma non è possibile utilizzare il termine "RESTful". Consiglio il libro O'Reilly su REST, che è molto leggibile e spiega l'argomento in profondità.
johndodo,

23
@skrebbel: la pura soluzione REST invierebbe i dati di autenticazione ogni volta che richiede una risorsa, il che è meno che perfetto (HTTP Auth fa questo). La soluzione proposta funziona ed è migliore per la maggior parte dei casi d'uso, ma non è RESTful. Non c'è bisogno di guerra, uso anche questa soluzione. Semplicemente non pretendo che sia RESTful. :)
johndodo

94
Oh andiamo, fai un esempio allora. Cos'altro è, che funziona bene? Mi piacerebbe davvero saperlo. HTTP Auth sicuramente no, non è possibile disconnettersi senza chiudere il browser e non è possibile offrire un UX di accesso decente senza molti JS non compatibili con il futuro specifici del browser. Non mi interessa molto di "puramente RESTful" vs "quasi RESTful" e dell'intero dibattito religioso associato, ma se dici che ci sono diversi modi, dovresti spiegarli.
skrebbel,

15
Un'autenticazione veramente RESTful con agenti utente del mondo reale (aka "browser") consiste in un cookie contenente il valore dell'autenticazione HTTP. In questo modo il server può fornire l'interfaccia utente per inserire login e password e il server può forzare il logout (eliminando il cookie). Inoltre, invece di rispondere 401 per richiedere l'accesso in caso di autenticazione non riuscita, il server deve utilizzare il reindirizzamento temporaneo per accedere alla schermata e, dopo aver eseguito correttamente l'accesso, reindirizzare temporaneamente alla posizione precedente. Inoltre, il server deve incorporare l'azione di disconnessione (modulo POST) praticamente in ogni pagina per gli utenti che hanno effettuato l'accesso.
Mikko Rantalainen,

15
Non vedo nulla di male nell'usare "riposante" e "sessione" nella stessa frase purché sia ​​chiaro che la sessione esiste solo sul lato client. Non sono sicuro del motivo per cui è stato fatto un così grande affare su questo concetto.
Joe Phillips,

140

Su questo argomento si dice già abbastanza da brave persone qui. Ma ecco i miei 2 centesimi.

Esistono 2 modalità di interazione:

  1. da uomo a macchina (HTM)
  2. machine-to-machine (MTM)

La macchina è il comune denominatore, espresso come API REST, e gli attori / clienti sono gli umani o le macchine.

Ora, in un'architettura veramente RESTful, il concetto di apolidia implica che tutti gli stati applicativi rilevanti (ovvero gli stati lato client) devono essere forniti con ogni richiesta. Per pertinente, si intende che tutto ciò che è richiesto dall'API REST per elaborare la richiesta e fornire una risposta appropriata.

Se lo consideriamo nel contesto di applicazioni da uomo a macchina, "basate sul browser" come sottolinea Skrebbel sopra, ciò significa che l'applicazione (web) in esecuzione nel browser dovrà inviare il suo stato e le informazioni pertinenti ad ogni richiesta rende le API REST di back-end.

Considera questo: hai una piattaforma dati / informazioni esposta asset di API REST. Forse hai una piattaforma BI self-service che gestisce tutti i cubi di dati. Ma vuoi che i tuoi clienti (umani) accedano tramite (1) app Web, (2) app mobile e (3) alcune applicazioni di terze parti. Alla fine, anche la catena di MTM porta a HTM - giusto. Pertanto, gli utenti umani rimangono all'apice della catena di informazione.

Nei primi 2 casi, hai un caso per l'interazione uomo-macchina, le informazioni vengono effettivamente consumate da un utente umano. Nell'ultimo caso, hai un programma macchina che utilizza le API REST.

Il concetto di autenticazione si applica a tutti i livelli. Come lo progetterai in modo tale che le tue API REST siano accessibili in modo uniforme e sicuro? Per come la vedo io, ci sono 2 modi:

Way-1:

  1. Non c'è accesso, per cominciare. Ogni richiesta esegue il login
  2. Il client invia i suoi parametri identificativi + i parametri specifici della richiesta ad ogni richiesta
  3. L'API REST li prende, si gira, esegue il ping dell'archivio utenti (qualunque cosa sia) e conferma l'autenticazione
  4. Se l'autenticazione è stabilita, soddisfa la richiesta; in caso contrario, nega con il codice di stato HTTP appropriato
  5. Ripeti quanto sopra per ogni richiesta in tutte le API REST nel tuo catalogo

Way-2:

  1. Il client inizia con una richiesta di autenticazione
  2. Un'API REST di accesso gestirà tutte queste richieste
  3. Comprende i parametri di autenticazione (chiave API, uid / pwd o qualunque cosa tu scelga) e verifica l'autenticità rispetto all'archivio utenti (LDAP, AD o DB MySQL ecc.)
  4. Se verificato, crea un token di autenticazione e lo restituisce al client / chiamante
  5. Il chiamante invia quindi questo token di autenticazione + richiede parametri specifici con ogni successiva richiesta ad altre API REST aziendali, fino alla disconnessione o fino alla scadenza del contratto di locazione

Chiaramente, in Way-2, le API REST avranno bisogno di un modo per riconoscere e ritenere il token valido. L'API di accesso ha eseguito la verifica dell'autenticazione e pertanto la "chiave del cameriere" deve essere considerata attendibile da altre API REST nel catalogo.

Ciò, ovviamente, significa che la chiave / token di autenticazione dovrà essere archiviata e condivisa tra le API REST. Questo repository di token condiviso e attendibile può essere locale / federato qualunque, consentendo alle API REST di altre organizzazioni di fidarsi l'una dell'altra.

Ma sto divagando.

Il punto è che uno "stato" (sullo stato autenticato del client) deve essere mantenuto e condiviso in modo che tutte le API REST possano creare un cerchio di fiducia. Se non lo facciamo, che è il Way-1, dobbiamo accettare che un atto di autenticazione debba essere eseguito per qualsiasi / tutte le richieste in arrivo.

L'esecuzione dell'autenticazione è un processo che richiede molte risorse. Immagina di eseguire query SQL, per ogni richiesta in arrivo, sul tuo archivio utenti per verificare la corrispondenza uid / pwd. Oppure, per crittografare ed eseguire corrispondenze hash (stile AWS). E dal punto di vista architettonico, ogni API REST dovrà eseguire questo, sospetto, usando un comune servizio di login back-end. Perché se non lo fai, allora sporchi il codice di autorizzazione ovunque. Un gran casino.

Quindi più livelli, più latenza.

Ora, prendi Way-1 e applica a HTM. Il tuo utente (umano) si preoccupa davvero se devi inviare uid / pwd / hash o altro con ogni richiesta? No, purché non la disturbi lanciando la pagina di autenticazione / accesso ogni secondo. Buona fortuna avere clienti se lo fai. Quindi, quello che farai è archiviare le informazioni di accesso da qualche parte sul lato client, nel browser, proprio all'inizio, e inviarle con ogni richiesta fatta. Per l'utente (umano), ha già effettuato l'accesso ed è disponibile una "sessione". Ma in realtà, è autenticata su ogni richiesta.

Lo stesso con Way-2. Il tuo utente (umano) non lo noterà mai. Quindi nessun danno è stato fatto.

Che cosa succede se applichiamo Way-1 a MTM? In questo caso, dal momento che è una macchina, possiamo annoiare questo ragazzo chiedendogli di inviare informazioni di autenticazione con ogni richiesta. A nessuno importa! L'esecuzione di Way-2 su MTM non evocherà alcuna reazione speciale; è una dannata macchina. Potrebbe importare di meno!

Quindi, davvero, la domanda è cosa soddisfa le tue esigenze. L'apolidia ha un prezzo da pagare. Paga il prezzo e vai avanti. Se vuoi essere un purista, allora paga anche il prezzo e vai avanti.

Alla fine, le filosofie non contano. Ciò che conta davvero è la scoperta di informazioni, la presentazione e l'esperienza di consumo. Se le persone adorano le tue API, hai fatto il tuo lavoro.


3
Signore, lo ha spiegato così magnificamente che ho una chiara idea della questione / domanda di base a portata di mano. Sei come il Buddha! Potrei aggiungere che usando HTTPS a livello di trasporto, possiamo persino prevenire gli attacchi Man In the Middle, in modo che nessuno possa dirottare la mia chiave identificativa (se viene scelto Way-1)
Vishnoo Rath,

Non è sempre una macchina che esegue l'autenticazione? L'essere umano non frega niente delle password, è uno sfortunato fastidio per gli utenti che razionalizzano correttamente la sicurezza. Per me è un problema per gli sviluppatori come vogliono che la macchina faccia il suo lavoro.
Todd Baur,

9
Ho letto la tua risposta; nella tua soluzione, per ogni singola richiesta web originata dal browser dai clic dell'utente dovrai inviare il "token di autenticazione" a qualsiasi API che l'utente clic sta chiamando. Cosa poi? L'API esegue il controllo sul token. Contro cosa? Contro una sorta di "token store" che mantiene se quel token è valido o meno. Non sei d'accordo sul fatto che quel "negozio di token" diventa quindi il custode di "stato"? In realtà, comunque tu lo veda, qualcuno da qualche parte deve sapere qualcosa sui "token" che vengono passati sulle attività degli utenti. Ecco dove vivono le informazioni sullo stato.
Kingz,

5
E per servizio "stateless", ciò che realmente si intende è che quel particolare componente server (le API CRUD) non porta alcuno stato. Non riconoscono un utente da un altro e completano la richiesta dell'utente nella sua interezza in una transazione. Questa è apolidia. Ma qualcuno da qualche parte deve essere seduto e giudicare se questo utente è valido o meno. Non c'è altro modo per farlo; chiavi o password o altro. Tutto ciò che viene trasmesso dal lato utente deve essere autenticato e autorizzato.
Kingz,

1
Manca Way-3l'approccio ibrido. Il client accede come in Way-2ma, come in Way-1, le credenziali non vengono verificate rispetto a nessuno stato lato server. Indipendentemente da ciò, un token di autenticazione viene creato e inviato al client come in Way-2. Questo token viene successivamente verificato per l'autenticità utilizzando la crittografia asimmetrica senza cercare uno stato specifico del client.
jcoffland,

50

Ecco una soluzione di autenticazione veramente e completamente RESTful:

  1. Creare una coppia di chiavi pubblica / privata sul server di autenticazione.
  2. Distribuire la chiave pubblica su tutti i server.
  3. Quando un client esegue l'autenticazione:

    3.1. emettere un token che contiene quanto segue:

    • Data di scadenza
    • nome utente (facoltativo)
    • IP utenti (opzionale)
    • hash di una password (opzionale)

    3.2. Crittografa il token con la chiave privata.

    3.3. Invia il token crittografato di nuovo all'utente.

  4. Quando l'utente accede a qualsiasi API, deve anche passare il proprio token di autenticazione.

  5. I server possono verificare che il token sia valido decodificandolo mediante la chiave pubblica del server di autenticazione.

Questa è l'autenticazione stateless / RESTful.

Si noti che se fosse incluso un hash di password, l'utente invierebbe anche la password non crittografata insieme al token di autenticazione. Il server ha potuto verificare che la password corrispondesse alla password utilizzata per creare il token di autenticazione confrontando gli hash. Sarebbe necessaria una connessione sicura usando qualcosa come HTTPS. Javascript sul lato client potrebbe gestire il recupero della password dell'utente e la sua memorizzazione sul lato client, in memoria o in un cookie, eventualmente crittografato con la chiave pubblica del server .


5
Cosa succede se qualcuno ottiene quel token di autenticazione e invoca API con esso fingendo di essere client?
Abidi,

2
@Abidi, sì, questo è un problema. Potresti richiedere una password. Un hash della password potrebbe essere incluso nel token di autenticazione. Se qualcuno fosse in grado di rubare il token sarebbe vulnerabile agli attacchi di forza bruta offline. Se si scegliesse una passphrase forte non sarebbe un problema. Si noti che se si utilizza il furto di token https richiederebbe all'utente malintenzionato di ottenere prima l'accesso alla macchina del client.
jcoffland,

1
Perché solo il server di autenticazione conosce la chiave privata. Altri server possono autenticare l'utente solo conoscendo la chiave pubblica e il token dell'utente.
jcoffland,

1
La crittografia e la decrittografia asimmetriche sono un ordine di grandezza più lento (più intenso in termini di calcolo) rispetto alla crittografia simmetrica. Avere il server utilizzando la chiave pubblica per decrittografare il token su ogni chiamata sarebbe un enorme collo di bottiglia delle prestazioni.
Craig,

3
@jcoffland hai davvero promosso la tua risposta qui (ripetutamente :-) Ma non posso fare a meno di commentare i problemi di prestazioni (intensità di calcolo) dell'uso della crittografia asimmetrica ad ogni chiamata. Non riesco proprio a vedere una soluzione che abbia quella capacità di ridimensionamento. Cerca HTTPS e il protocollo SPDY. Fa di tutto per mantenere aperte le connessioni (keep-alive HTTP, che è stato) e servire più risorse in batch sulla stessa connessione (più stato) e, naturalmente, lo stesso SSL utilizza solo la crittografia asimmetrica per scambiare una chiave di crittografia simmetrica ( anche stato).
Craig,

37

Ad essere sincero con te ho visto grandi risposte qui, ma qualcosa che mi preoccupa un po 'è quando qualcuno porterà il concetto di apolide a un estremo dove diventa dogmatico. Mi ricorda quei vecchi fan di Smalltalk che volevano solo abbracciare OO puro e se qualcosa non è un oggetto, allora stai sbagliando. Dammi una pausa.

L'approccio RESTful dovrebbe semplificarti la vita e ridurre il sovraccarico e il costo delle sessioni, provare a seguirla perché è una cosa saggia da fare, ma nel momento in cui segui una disciplina (qualsiasi disciplina / linea guida) all'estremo dove essa non fornisce più il vantaggio a cui era destinato, quindi stai sbagliando. Alcuni dei migliori linguaggi oggi hanno sia la programmazione funzionale che l'orientamento agli oggetti.

Se il modo più semplice per risolvere il problema è archiviare la chiave di autenticazione in un cookie e inviarlo sull'intestazione HTTP, quindi farlo, non abusarne. Ricorda che le sessioni sono cattive quando diventano pesanti e grandi, se tutta la tua sessione è composta da una breve stringa contenente una chiave, qual è il grosso problema?

Sono aperto ad accettare correzioni nei commenti, ma non vedo il punto (finora) di rendere miserabili le nostre vite per evitare semplicemente di tenere un grande dizionario di hash nel nostro server.


2
Le persone non stanno cercando di vietarti di utilizzare le sessioni. Sei libero di farlo. Ma se lo fai, non è RIPOSO.
André Caldas,

6
@ AndréCaldas non è REST allo stesso modo in cui avere funzioni o tipi primitivi in ​​una lingua non è oop. Non sto dicendo che è consigliabile avere sessioni. Sto solo esprimendo la mia opinione riguardo al seguire una serie di pratiche nella misura in cui non offrono più benefici a qualcuno. (A proposito, nota che non mi sono opposto alle tue osservazioni, tuttavia, non direi che non è REST, direi che non è puro REST).
arg20,

Quindi come lo chiamiamo se non è RESTful? E sicuramente se una richiesta include l'ID sessione, allora è senza stato come una richiesta che include un ID utente? Perché l'ID utente e lo stato sessione sono stateful?
mfhholmes,

1
I cookie sono vulnerabili alla falsificazione di richieste tra siti, quindi semplificano le violazioni della sicurezza. Meglio usare qualcosa che non viene inviato automaticamente dal browser come un'intestazione personalizzata o uno schema di autorizzazione personalizzato.
Dobes Vandermeer,

1
In realtà, cercare di essere apolidi non riguarda il dogmatismo, ma una concezione comune della SOA stessa. I servizi dovrebbero sempre trarre vantaggio dall'essere disaccoppiati e apolidi: in pratica, facilita il ridimensionamento, la disponibilità e la manutenibilità. Certo, dovrebbe essere il più possibile e alla fine avresti bisogno di alcuni "servizi di orchestrazione" per gestire quei servizi senza stato in un approccio pragmatico con stato.
Arnaud Bouchez,

32

In primo luogo, un servizio web RESTful è STATELESS (o in altre parole, senza sessione). Pertanto, un servizio RESTful non ha e non dovrebbe avere un concetto di sessione o cookie coinvolti. Il modo per eseguire l'autenticazione o l'autorizzazione nel servizio RESTful è utilizzare l'intestazione Autorizzazione HTTP come definito nelle specifiche HTTP RFC 2616. Ogni singola richiesta deve contenere l'intestazione di autorizzazione HTTP e la richiesta deve essere inviata tramite una connessione HTTP (SSL). Questo è il modo corretto di eseguire l'autenticazione e verificare l'autorizzazione delle richieste in un servizio Web HTTP RESTful. Ho implementato un servizio Web RESTful per l'applicazione Cisco PRIME Performance Manager presso Cisco Systems. E come parte di quel servizio web, ho implementato anche l'autenticazione / autorizzazione.


5
L'autenticazione HTTP richiede ancora che il server tenga traccia degli ID utente e delle password. Questo non è completamente apolide.
jcoffland,

21
È apolide nel senso che ogni richiesta è valida da sola senza alcun requisito delle richieste precedenti. Il modo in cui questo è implementato sul server è un'altra cosa, se l'autenticazione è costosa potresti fare un po 'di memorizzazione nella cache e riautenticare in caso di mancanza della cache. Pochissimi server sono completamente senza stato in cui l'output è puramente una funzione dell'input. Di solito è una query o un aggiornamento di alcuni stati.
Erik Martino,

3
Non vero. In questo caso, tutte le richieste richiedono lo stato di una transazione precedente, vale a dire la registrazione dell'utente. Non vedo perché la gente continui a provare a dire che un nome utente e una password memorizzati sul server non sono stati lato server. Vedi la mia risposta
jcoffland,

1
@jcoffland Inoltre, la soluzione si basa fortemente sulla capacità del server API di decrittografare il token firmato. Penso che questo approccio non sia solo troppo specifico, ma anche un po 'troppo sofisticato per essere considerato come THE approah R. Fielding aveva in mente di affrontare il problema dell'autenticazione RESTful.
Michael Ekoka,

2
@jcoffland capisci quanto sia crittografia asimmetrica profondamente più intensiva in termini di calcolo (e quindi intensiva in termini di risorse e profondamente lenta)? Stai parlando di uno schema che userebbe la crittografia asimmetrica su ogni singola richiesta. L'aspetto più lento di HTTPS, salvo nulla, è la stretta di mano iniziale che prevede la creazione di chiavi pubbliche / private per crittografare asimmetricamente un segreto condiviso che viene successivamente utilizzato per crittografare simmetricamente tutte le comunicazioni che ne conseguono.
Craig,

22

Non si tratta certamente di "chiavi di sessione" in quanto viene generalmente utilizzato per fare riferimento all'autenticazione senza sessione che viene eseguita all'interno di tutti i vincoli di REST. Ogni richiesta è auto-descrittiva e contiene informazioni sufficienti per autorizzare la richiesta da sola senza alcuno stato dell'applicazione sul lato server.

Il modo più semplice per affrontarlo è iniziare con i meccanismi di autenticazione integrati di HTTP in RFC 2617 .


L'autenticazione HTTP richiede che il server memorizzi il nome utente e la password. Questo è lo stato lato server e quindi non rigorosamente REST. Vedi la mia risposta
jcoffland,

3
@jcoffland: semplicemente non è vero, su entrambi i conti. La prima autenticazione HTTP non richiede al server di memorizzare la password. L' hash della password viene invece memorizzato (bcrypt con 8+ round consigliati). In secondo luogo, il server non ha alcun stato poiché l'intestazione di autorizzazione viene inviata con ogni richiesta. E se consideri gli hash delle password memorizzati come stato , non sono più lo stato di quanto lo siano le chiavi pubbliche memorizzate.
Boris B.

1
@Boris B., sì, capisco che la password è memorizzata come hash. La password con hash è ancora stato specifico del client. La differenza con l'archiviazione di una chiave pubblica, come descritto nella mia soluzione, è che esiste solo una chiave pubblica, la chiave pubblica del server di autenticazione. Questo è molto diverso dalla memorizzazione di un hash di password per utente. Non importa come lo vesti se il server memorizza una password per ciascun utente, quindi lo sta memorizzando per stato dell'utente e non è REST al 100%.
jcoffland,

7
Non credo che l'archiviazione di una password con hash degli utenti sul server debba essere considerata uno stato lato server. Gli utenti sono risorse che contengono informazioni come nome, indirizzo o password con hash.
Codepunkt,

15

L'articolo "molto penetrante" menzionato da @skrebel ( http://www.berenddeboer.net/rest/authentication.html ) discute di un metodo di autenticazione contorto ma veramente rotto.

Puoi provare a visitare la pagina (che dovrebbe essere visibile solo all'utente autenticato) http://www.berenddeboer.net/rest/site/authenticated.html senza credenziali di accesso.

(Mi dispiace non posso commentare la risposta.)

Direi che REST e autenticazione semplicemente non si mescolano. REST significa apolide ma "autenticato" è uno stato. Non puoi averli entrambi sullo stesso livello. Se sei un sostenitore di RESTful e disapprovi gli stati, allora devi andare con HTTPS (cioè lasciare il problema di sicurezza su un altro livello).


Stripe.com direbbe diversamente al tuo commento su REST e autenticazione che non si mescolano ..
Erik,

Stateless si riferisce solo al server, non al client. Il cliente può ricordare tutto lo stato della sessione e inviare ciò che è rilevante per ogni richiesta.
Dobes Vandermeer,

Finalmente qualcuno parla un po 'di senso, ma l'autenticazione senza stato è possibile usando la crittografia a chiave pubblica. Vedi la mia risposta
jcoffland,

1
Il server non ha uno stato "autenticato". Riceve informazioni tramite hypermedia e deve lavorare con esso per restituire ciò che è stato richiesto. Niente di meno, niente di più. Se la risorsa è protetta e richiede autenticazione e autorizzazione, l'hypermedia fornito deve includere tali informazioni. Non so da dove provenga l'idea che autenticare un utente prima di restituire una risorsa significhi che il server sta monitorando lo stato. Fornire un nome utente e una password può benissimo essere pensato semplicemente come fornire più parametri di filtro.
Michael Ekoka,

"Direi che REST e autenticazione semplicemente non si mescolano." Sembra un po 'di buon senso. Solo che un sistema incompatibile con l'autenticazione ("autenticato" stesso è, ovviamente, uno stato) è di utilità limitata. Sento che stiamo discutendo tutti all'intersezione di praticità e dogmatismo purista, e francamente la praticità dovrebbe vincere. Ci sono molti aspetti di REST che sono molto utili senza entrare in contorsioni cercando di evitare lo stato rispetto all'autenticazione, vero?
Craig,

12

Penso che l'autenticazione riposante implichi il passaggio di un token di autenticazione come parametro nella richiesta. Esempi sono l'uso di apikeys da parte di api. Non credo che l'uso dei cookie o dell'autenticazione http sia valido.


I cookie e HTTP Auth dovrebbero essere evitati a causa della vulnerabilità CSRF.
Dobes Vandermeer,

@DobesVandermeer Puoi per favore vedere la mia domanda se puoi aiutare? stackoverflow.com/questions/60111743/…
Hemant Metalia il

12

Aggiornamento il 16 febbraio 2019

L'approccio menzionato in precedenza è essenzialmente il tipo di concessione "Credenziali password proprietario risorsa" di OAuth2.0 . Questo è un modo semplice per iniziare. Tuttavia, con questo approccio ogni applicazione dell'organizzazione finirà con i propri meccanismi di autenticazione e autorizzazione. L'approccio raccomandato è il tipo di concessione "Codice di autorizzazione". Inoltre, nella mia risposta precedente di seguito, ho raccomandato localStorage del browser per la memorizzazione dei token di autenticazione. Tuttavia, sono arrivato a credere che i cookie siano l'opzione giusta per questo scopo. Ho dettagliato i miei motivi, l'approccio all'implementazione del tipo di concessione del codice di autorizzazione, considerazioni sulla sicurezza ecc. In questa risposta StackOverflow .


Penso che il seguente approccio possa essere utilizzato per l'autenticazione del servizio REST:

  1. Creare un'API RESTful di accesso per accettare nome utente e password per l'autenticazione. Utilizzare il metodo HTTP POST per impedire la memorizzazione nella cache e SSL per la sicurezza durante il transito In caso di autenticazione riuscita, l'API restituisce due JWT: un token di accesso (validità più breve, diciamo 30 minuti) e un token di aggiornamento (validità più lunga, diciamo 24 ore)
  2. Il client (un'interfaccia utente basata sul Web) archivia i JWT nella memoria locale e in ogni successiva chiamata API passa il token di accesso nell'intestazione "Autorizzazione: Bearer #access token"
  3. L'API verifica la validità del token verificando la firma e la data di scadenza. Se il token è valido, controlla se l'utente (interpreta il reclamo "sub" in JWT come nome utente) ha accesso all'API con una ricerca nella cache. Se l'utente è autorizzato ad accedere all'API, eseguire la logica aziendale
  4. Se il token è scaduto, l'API restituisce il codice di risposta HTTP 400
  5. Il client, alla ricezione di 400/401, richiama un'altra API REST con il token di aggiornamento nell'intestazione "Autorizzazione: Bearer #refresh token" per ottenere un nuovo token di accesso.
  6. Alla ricezione della chiamata con il token di aggiornamento, verificare se il token di aggiornamento è valido controllando la firma e la data di scadenza. Se il token di aggiornamento è valido, aggiornare la cache dei diritti di accesso dell'utente dal DB e restituire il nuovo token di accesso e il token di aggiornamento. Se il token di aggiornamento non è valido, restituire il codice di risposta HTTP 400
  7. Se vengono restituiti un nuovo token di accesso e un token di aggiornamento, andare al passaggio 2. Se viene restituito il codice di risposta HTTP 400, il client presume che il token di aggiornamento sia scaduto e richiede all'utente nome utente e password
  8. Per la disconnessione, eliminare la memoria locale

Con questo approccio stiamo eseguendo la costosa operazione di caricamento della cache con i dettagli dei diritti di accesso specifici dell'utente ogni 30 minuti. Pertanto, se un accesso viene revocato o viene concesso un nuovo accesso, sono necessari 30 minuti per riflettere o un logout seguito da un accesso.


quindi lo useresti per un API con un sito web statico realizzato ad esempio con angolare? e che dire delle app mobili?
Yazan Rawashdeh,

8

Questo è il modo per farlo: usare OAuth 2.0 per l'accesso .

Puoi utilizzare altri metodi di autenticazione diversi da quelli di Google purché supportino OAuth.


1
OAuth2 non è sicuro senza HTTPS, né stateless.
Arnaud Bouchez,

4
Niente è sicuro senza HTTPS.
Craig,

1
Anche @Craig e HTTPS potrebbero non essere sicuri, se la catena di certificati viene spezzata, il che potrebbe essere per maggior bene - en.wikipedia.org/wiki/Bullrun_(decryption_program) ;)
Arnaud Bouchez,

1
@ArnaudBouchez Per favore, chiarisci come avere una catena di certificati spezzata è per un bene superiore? Non capisco dove stai andando con quello. ;)
Craig,

@Craig Segui il link e divertiti! Questo approccio al "bene superiore" era chiaramente cinico nel mio commento: i sistemi simili a Bullrun sono pensati per il "nostro bene" dai nostri governi amati e fiduciosi.
Arnaud Bouchez,

3

L'uso di un'infrazione di chiave pubblica in cui la registrazione di una chiave implica un'adeguata associazione garantisce che la chiave pubblica sia vincolata all'individuo a cui è assegnata in modo da garantire il non ripudio

Vedi http://en.wikipedia.org/wiki/Public_key_infrastructure . Se si seguono gli standard PKI corretti, la persona o l'agente che utilizza in modo improprio la chiave rubata può essere identificato e bloccato. Se l'agente deve utilizzare un certificato, l'associazione diventa piuttosto stretta. Un ladro intelligente e in rapido movimento può fuggire, ma lasciano più briciole.


2

Per rispondere a questa domanda dalla mia comprensione ...

Un sistema di autenticazione che utilizza REST in modo da non dover effettivamente tracciare o gestire gli utenti nel tuo sistema. Questo viene fatto usando i metodi HTTP POST, GET, PUT, DELETE. Prendiamo questi 4 metodi e li consideriamo in termini di interazione con il database come CREATE, READ, UPDATE, DELETE (ma sul web usiamo POST e GET perché questo è ciò che attualmente supporta i tag di ancoraggio). Quindi trattando POST e GET come il nostro CREATE / READ / UPDATE / DELETE (CRUD), allora possiamo progettare percorsi nella nostra applicazione Web che saranno in grado di dedurre quale azione di CRUD stiamo realizzando.

Ad esempio, in un'applicazione Ruby on Rails possiamo creare la nostra app Web in modo tale che se un utente che ha effettuato l'accesso visiti http://store.com/account/logout il GET di quella pagina possa essere visualizzato come l'utente che tenta di disconnettersi . Nel nostro controller di rotaie avremmo creato un'azione che disconnettesse l'utente e lo rimandasse alla home page.

Un GET sulla pagina di accesso genererebbe un modulo. un POST sulla pagina di accesso verrebbe visualizzato come un tentativo di accesso e prendere i dati POST e usarli per accedere.

Per me, è una pratica utilizzare metodi HTTP mappati sul significato del loro database e quindi costruire un sistema di autenticazione tenendo presente che non è necessario passare da un ID di sessione o tenere traccia delle sessioni.

Sto ancora imparando: se trovi qualcosa che ho detto di essere sbagliato, per favore correggimi e se impari di più pubblicalo di nuovo qui. Grazie.


2

Suggerimenti validi per proteggere qualsiasi applicazione Web

Se vuoi proteggere la tua applicazione, allora dovresti assolutamente iniziare a usare HTTPS invece di HTTP , questo assicura un canale sicuro tra te e gli utenti che impedirà di annusare i dati inviati avanti e indietro agli utenti e aiuterà a conservare i dati scambiato confidenziale.

È possibile utilizzare JWT (token Web JSON) per proteggere le API RESTful , questo ha molti vantaggi rispetto alle sessioni lato server, i vantaggi sono principalmente:

1- Più scalabile, poiché i tuoi server API non dovranno mantenere sessioni per ciascun utente (il che può essere un grosso fardello quando hai molte sessioni)

2- I JWT sono autonomi e hanno i reclami che definiscono ad esempio il ruolo dell'utente e ciò a cui può accedere e rilasciare alla data e alla data di scadenza (dopo la quale JWT non sarà valido)

3- Più facile da gestire attraverso i servizi di bilanciamento del carico e se si dispone di più server API in quanto non è necessario condividere i dati della sessione né configurare il server per indirizzare la sessione allo stesso server, ogni volta che una richiesta con un JWT raggiunge qualsiasi server può essere autenticata e autorizzato

4- Meno pressione sul DB e non sarà necessario archiviare e recuperare costantemente ID sessione e dati per ogni richiesta

5- I JWT non possono essere manomessi se si utilizza una chiave avanzata per firmare il JWT, quindi è possibile fidarsi dei reclami nel JWT inviati con la richiesta senza dover controllare la sessione dell'utente e se è autorizzato o meno , puoi semplicemente controllare JWT e sei pronto a sapere chi e cosa può fare questo utente.

Molte librerie offrono modi semplici per creare e validare JWT nella maggior parte dei linguaggi di programmazione, ad esempio: in node.js uno dei più popolari è jsonwebtoken

Poiché le API REST generalmente mirano a mantenere il server senza stato, quindi i JWT sono più compatibili con quel concetto in quanto ogni richiesta viene inviata con token di autorizzazione autonomo (JWT) senza che il server debba tenere traccia della sessione dell'utente rispetto alle sessioni che rendono il server stateful in modo che ricordi l'utente e il suo ruolo, tuttavia, le sessioni sono anche ampiamente utilizzate e hanno i loro pro, che puoi cercare se vuoi.

Una cosa importante da notare è che devi consegnare in modo sicuro il JWT al client usando HTTPS e salvarlo in un luogo sicuro (ad esempio nella memoria locale).

Puoi saperne di più sui JWT da questo link

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.