Autenticazione RESTful

Che cosa significa RESTful Authentication e come funziona? Non riesco a trovare una buona panoramica su Google. La mia unica comprensione è che si passa la chiave di sessione (remeberal) nell’URL, ma questo potrebbe essere terribilmente sbagliato.

Come gestire l’autenticazione in un’architettura client-server REST è una questione di dibattito.

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

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

Dovrai adattare, o meglio ancora mescolare queste tecniche, per armonizzare al meglio la tua architettura software.

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

Autenticazione di base HTTP su HTTPS

Questa prima soluzione, basata sul protocollo HTTPS standard, viene 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 ha alcuni svantaggi noti, come la terribile finestra di autenticazione visualizzata sul browser, che persisterà (non esiste una funzionalità simile a LogOut qui), qualche CPU aggiuntiva lato server consumo e il fatto che il nome utente e la password siano trasmessi (tramite HTTPS) nel Server (dovrebbe essere più sicuro lasciare che la password rimanga solo sul lato client, durante l’immissione dalla tastiera, e essere archiviata come hash sicuro sul Server).

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

Sessione tramite cookie

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

Una possibilità potrebbe essere quella di mantenere tutti i dati all’interno del contenuto dei cookie. E, dal punto di vista della progettazione, il cookie viene gestito sul lato Server (il Cliente infatti non tenta nemmeno di interpretare questi dati sui cookie: li restituisce semplicemente al server in ogni richiesta successiva). Ma questi dati sui cookie sono dati sullo stato dell’applicazione, quindi il client dovrebbe gestirlo, non il server, in un mondo puramente stateless.

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

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

Concesso tramite token (OAuth2)

Un’alternativa è mettere un token all’interno delle intestazioni HTTP, in modo che la richiesta sia autenticata. Questo è ciò che fa OAuth 2.0, per esempio. Vedi la 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 soffre degli stessi problemi: non stateless, basato su dettagli di trasmissione HTTP e sobject a molte debolezze di sicurezza – tra cui MiM e Replay – quindi deve essere utilizzato solo su HTTPS.

Autenticazione della query

L’autenticazione della query consiste nel firmare ciascuna 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 di query ordinati in minuscolo, in ordine alfabetico utilizzando le credenziali private come token di firma. La firma dovrebbe avvenire prima della codifica URL della stringa di query.

Questa tecnica è forse la più compatibile con un’architettura Stateless e può anche essere implementata con una gestione della sessione leggera (utilizzando sessioni in memoria anziché la persistenza DB).

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

 GET /object?apiKey=Qwerty2010 

dovrebbe essere trasmesso come tale:

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

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

La cache dei dati sul lato server può essere sempre disponibile. Ad esempio, nel nostro framework, memorizziamo le risposte in cache a livello SQL, non a livello di URI. Quindi l’aggiunta di questo parametro aggiuntivo non interrompe il meccanismo della cache.

Consulta questo articolo per alcuni dettagli sull’autenticazione RESTful nel nostro framework ORM / SOA / MVC client-server, basato su JSON e REST. Dal momento che consentiamo la comunicazione non solo su HTTP / 1.1, ma anche su named pipe o messaggi GDI (localmente), abbiamo cercato di implementare un pattern di autenticazione veramente RESTful e non fare affidamento sulla specificità HTTP (come header o cookies).

In pratica, l’imminente autenticazione dei token MAC per OAuth 2.0 potrebbe rappresentare un enorme miglioramento rispetto allo schema corrente “Concesso da token”. Ma questo è ancora un work in progress, ed è legato alla trasmissione HTTP.

Conclusione

Vale la pena concludere che REST non è solo basato su HTTP, anche se, in pratica, è implementato principalmente su HTTP. REST può utilizzare 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 il meccanismo HTTP, ma deve essere astratto dal livello di comunicazione.

Dubito che le persone che gridano entusiasticamente “Autenticazione HTTP” abbiano mai provato a creare un’applicazione basata su browser (anziché un servizio web machine-to-machine) con REST (senza offesa intesa – non penso che abbiano mai dovuto affrontare le complicazioni) .

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

  • l’utente in genere ha una brutta finestra di login creata dal browser, che è molto poco amichevole all’utente. non è ansible aggiungere il recupero della password, le caselle della guida, ecc.
  • disconnettersi o accedere con un nome diverso è un problema: i browser continueranno a inviare le informazioni di autenticazione al sito finché non si chiude la finestra
  • i timeout sono difficili

Un articolo molto interessante che affronta questi punti per punto è qui , ma questo si traduce in un sacco di hackery javascript specifici del browser, soluzioni alternative per soluzioni alternative, eccetera. In quanto tale, non è compatibile anche con il futuro, quindi richiederà una manutenzione costante man mano che i nuovi browser vengono rilasciati. Non considero questo design pulito e chiaro, inoltre ritengo che ci sia un sacco di lavoro extra e mal di testa solo per poter mostrare con entusiasmo il mio badge REST ai miei amici.

Credo che i biscotti siano la soluzione. Ma aspetta, i biscotti sono cattivi, no? No, non lo sono, il modo in cui i cookie vengono spesso usati è il male. Un cookie di per sé è solo una parte delle informazioni sul lato client, proprio come le informazioni di autenticazione HTTP che il browser manterrebbe traccia durante la navigazione. E questa parte di informazioni sul lato client viene inviata al server ad ogni richiesta, sempre come le informazioni di autenticazione HTTP. Concettualmente, l’unica differenza è che il contenuto di questo pezzo di stato 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 mappa una chiave per un id utente (e possibilmente un timestamp dell’ultima azione per i timeout)
  • Se esiste una sessione , significa che la chiave è valida.
  • Login significa POST a / sessioni, una nuova chiave è impostata come cookie
  • Logout significa DELETEing / sessions / {chiave} (con 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 controllando se la sessione esiste ed è valida

L’unica differenza con l’autenticazione HTTP, ora, è che la chiave di autenticazione viene generata dal server e inviata al client che continua a inviarlo, anziché al client che la calcola dalle credenziali immesse.

converter42 aggiunge che quando si utilizza https (che dovremmo), è importante che il cookie abbia il proprio flag sicuro 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 inphp, HttpSession in Java EE, ecc.). I contenuti dell’intestazione del cookie sono semplicemente usati per indirizzare una risorsa lato server, proprio come potrebbe essere usato un linguaggio accettabile per accedere alle risorse di traduzione, eccetera. Sento che è lo stesso, ma forse altri no? Cosa ne pensi, ragazzi?

Basta già dire su questo argomento da bravi ragazzi qui. Ma ecco i miei 2 centesimi.

Ci sono 2 modalità di interazione:

  1. human-to-machine (HTM)
  2. machine-to-machine (MTM)

La macchina è il comune denominatore, espressa 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 del lato client) devono essere forniti con ogni singola richiesta. Per pertinenza, si intende che qualunque cosa sia richiesta dall’API REST per elaborare la richiesta e fornire una risposta appropriata.

Quando lo consideriamo nel contesto di applicazioni human-to-machine, “browser based” come indicato da Skrebbel sopra, ciò significa che l’applicazione (web) in esecuzione nel browser dovrà inviare il suo stato e le informazioni rilevanti ad ogni richiesta rende alle API REST back-end.

Considera questo: hai una piattaforma dati / informazioni esposta come set 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 questa (1) app web, (2) app mobile e (3) alcune applicazioni di terze parti. Alla fine, anche una catena di MTM conduce fino a HTM – giusto. Quindi gli utenti umani rimangono al vertice della catena di informazioni.

Nei primi 2 casi, si ha un caso per l’interazione uomo-macchina, poiché l’informazione viene effettivamente consumata 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 progetterai questo in modo che le tue API REST siano accessibili in modo uniforms e sicuro? Il modo in cui vedo questo, ci sono 2 modi:

Way-1:

  1. Non c’è accesso per cominciare. Ogni richiesta esegue il login
  2. Il client invia i suoi parametri di identificazione + i parametri specifici della richiesta con ogni richiesta
  3. L’API REST li prende, gira, fa ping all’archivio utente (qualunque cosa sia) e conferma l’autenticazione
  4. Se l’autenticazione è stabilita, fornisce la richiesta; in caso contrario, nega con il codice di stato HTTP appropriato
  5. Ripeti il ​​precedente per ogni richiesta su tutte le API REST nel tuo catalogo

Way-2:

  1. Il client inizia con una richiesta di authorization
  2. Un’API REST di accesso gestirà tutte queste richieste
  3. Accetta i parametri auth (chiave API, uid / pwd o qualsiasi altra cosa tu scelga) e verifica l’autenticazione contro l’archivio utente (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 richiesta successiva ad altre API REST aziendali, fino alla disconnessione o fino alla scadenza del leasing

Chiaramente, nel Way-2, le API REST avranno bisogno di un modo per riconoscere e considerare attendibile il token come valido. L’API di accesso ha eseguito la verifica dell’autenticazione e pertanto la “chiave di valet” deve essere considerata attendibile da altre API REST nel catalogo.

Questo ovviamente significa che la chiave / token di autenticazione dovrà essere archiviata e condivisa tra le API REST. Questo repository token condiviso e affidabile può essere locale / federato, consentendo alle API REST di altre organizzazioni di fidarsi l’un l’altro.

Ma sto divagando.

Il punto è che uno “stato” (relativo allo stato autenticato del client) deve essere mantenuto e condiviso in modo che tutte le API REST possano creare una cerchia di fiducia. Se non facciamo questo, che è il Way-1, dobbiamo accettare che un atto di autenticazione deve essere eseguito per qualsiasi / tutte le richieste che arrivano.

L’esecuzione dell’autenticazione è un processo che richiede molte risorse. Immagina di eseguire query SQL, per ogni richiesta in arrivo, contro il tuo negozio utente per verificare la corrispondenza uid / pwd. Oppure, per crittografare e eseguire le corrispondenze hash (lo stile AWS). E, architettonicamente, ogni API REST dovrà eseguire questo, credo, utilizzando un comune servizio di accesso back-end. Perché, se non lo fai, allora rifiuti il ​​codice di autenticazione ovunque. Un gran casino.

Quindi più gli strati, più latenza.

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

Lo stesso con Way-2. Il tuo utente (umano) non se ne accorgerà mai. Quindi niente male fatto.

Cosa succede se applichiamo Way-1 a MTM? In questo caso, dal momento che è una macchina, possiamo annoiare fuori da questo ragazzo chiedendogli di inviare le informazioni di autenticazione ad ogni richiesta. A nessuno importa! Eseguire Way-2 su MTM non evocherà alcuna reazione speciale; è una maledetta macchina. Potrebbe importare di meno!

Quindi, davvero, la domanda è quella che si adatta alle tue necessità. L’apolidia ha un prezzo da pagare. Paga il prezzo e vai avanti. Se vuoi essere un purista, paga anche il prezzo per questo e vai avanti.

Alla fine, le filosofie non contano. Ciò che veramente importa è la scoperta delle informazioni, la presentazione e l’esperienza di consumo. Se la gente ama le tue API, hai fatto il tuo lavoro.

Ecco una soluzione di autenticazione veramente e completamente RESTful:

  1. Creare una coppia di chiavi pubblica / privata sul server di autenticazione.
  2. Distribuisci la chiave pubblica a tutti i server.
  3. Quando un client si autentica:

    3.1. emettere un token che contiene quanto segue:

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

    3.2. Cripta il token con la chiave privata.

    3.3. Invia il token crittografato all’utente.

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

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

Questa è l’autenticazione stateless / RESTful.

Si noti che, se è stato incluso un hash della password, l’utente invierà anche la password non crittografata insieme al token di autenticazione. Il server può verificare che la password corrisponda 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 l’archiviazione lato client, sia in memoria che in un cookie, possibilmente crittografato con la chiave pubblica del server.

Per essere onesto con te ho visto grandi risposte qui, ma qualcosa che mi disturba un po ‘è quando qualcuno porterà l’intero concetto di Stateless ad un estremo dove diventa dogmatico. Mi ricorda quei vecchi fan di Smalltalk che volevano solo abbracciare OO puro e se qualcosa non è un object, allora lo stai facendo male. Dammi una pausa.

L’approccio RESTful dovrebbe semplificarti la vita e ridurre il sovraccarico e il costo delle sessioni, cerca di seguirlo in quanto è una cosa saggia da fare, ma nel momento in cui segui una disciplina (qualsiasi disciplina / linea guida) fino all’estremo in cui non fornisce più il vantaggio per cui era stato progettato, quindi lo stai facendo male. Alcune delle migliori lingue oggi hanno sia la programmazione funzionale che l’orientamento degli oggetti.

Se il modo più semplice per risolvere il tuo problema è archiviare la chiave di autenticazione in un cookie e inviarla sull’intestazione HTTP, quindi fallo, non abusarne. Ricorda che le sessioni sono cattive quando diventano pesanti e grandi, se tutta la tua sessione consiste in una stringa breve contenente una chiave, allora qual è il problema?

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

Prima di tutto, un servizio web RESTful è STATELESS (o in altre parole SESSIONLESS ). 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’authorization nel servizio RESTful è utilizzando l’intestazione di authorization HTTP come definita nelle specifiche HTTP 26C RFC. Ogni singola richiesta dovrebbe contenere l’intestazione di authorization HTTP e la richiesta dovrebbe essere inviata tramite una connessione HTTP (SSL). Questo è il modo corretto di eseguire l’autenticazione e verificare l’authorization delle richieste in un servizio web RESTful HTTP. 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 / authorization.

Rubens Gomes.

Non si tratta certamente di “chiavi di sessione” in quanto viene generalmente utilizzato per riferirsi all’autenticazione senza sessione che viene eseguita all’interno di tutti i vincoli di REST. Ogni richiesta è auto-descrittiva, contiene abbastanza informazioni per autorizzare la richiesta da sola senza alcun stato di applicazione sul lato server.

Il modo più semplice per avvicinarsi a questo è iniziare con i meccanismi di autenticazione incorporati di HTTP in RFC 2617 .

L’articolo “molto perspicace” menzionato da @skrebel ( http://www.berenddeboer.net/rest/authentication.html ) discute un metodo di autenticazione complicato ma molto rotto.

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

(Scusate, non posso commentare la risposta).

Direi REST e l’autenticazione semplicemente non si mescolano. REST significa senza stato ma “autenticato” è uno stato. Non puoi averli entrambi allo stesso livello. Se sei un sostenitore RESTful e disapprovi gli stati, allora devi andare con HTTPS (cioè lasciare il problema di sicurezza ad un altro livello).

I think restful authentication involves the passing of an authentication token as a parameter in the request. Examples are the use of apikeys by api’s. I don’t believe the use of cookies or http auth qualifies.

I think the following approach can be used for REST service authentication:

  1. Create a login RESTful API to accept username and password for authentication. Use HTTP POST method to prevent caching and SSL for security during transit On successful authentication, the API returns two JWTs – one access token (shorter validity, say 30 minutes) and one refresh token (longer validity, say 24 hours)
  2. The client (a web based UI) stores the JWTs in local storage and in every subsequent API call passes the access token in “Authorization: Bearer #access token” header
  3. The API checks the validity of the token by verifying the signature and expiry date. If the token is valid, check if the user (It interprets the “sub” claim in JWT as username) has access to the API with a cache lookup. If the user is authorized to access the API, execute the business logic
  4. If the token is expired, the API returns HTTP response code 400
  5. The client, on receiving 400/401, invokes another REST API with the refresh token in “Authorization: Bearer #refresh token” header to get a new access token.
  6. On receiving the call with refresh token, check if the refresh token is valid by checking the signature and the expiry date. If the refresh token is valid, refresh the access right cache of the user from DB and return new access token and refresh token. If the refresh token is invalid, return HTTP response code 400
  7. If a new access token and refresh token are returned, go to step 2. If HTTP response code 400 is returned, the client assumes that the refresh token has expired and asks for username and password from the user
  8. For logout, purge the local storage

With this approach we are doing the expensive operation of loading the cache with user specific access right details every 30 minutes. So if an access is revoked or new access is granted, it takes 30 minutes to reflect or a logout followed by a login.

That’s the way to do that: Using OAuth 2.0 for Login .

You may use other authentication methods other then Google’s as long as it supports OAuth.

To answer this question from my understanding…

An authentication system that uses REST so that you do not need to actually track or manage the users in your system. This is done by using the HTTP methods POST, GET, PUT, DELETE. We take these 4 methods and think of them in terms of database interaction as CREATE, READ, UPDATE, DELETE (but on the web we use POST and GET because that is what anchor tags support currently). So treating POST and GET as our CREATE/READ/UPDATE/DELETE (CRUD) then we can design routes in our web application that will be able to deduce what action of CRUD we are achieving.

For example, in a Ruby on Rails application we can build our web app such that if a user who is logged in visits http://store.com/account/logout then the GET of that page can viewed as the user attempting to logout. In our rails controller we would build an action in that logs the user out and sends them back to the home page.

A GET on the login page would yield a form. a POST on the login page would be viewed as a login attempt and take the POST data and use it to login.

To me, it is a practice of using HTTP methods mapped to their database meaning and then building an authentication system with that in mind you do not need to pass around any session id’s or track sessions.

I’m still learning — if you find anything I have said to be wrong please correct me, and if you learn more post it back here. Grazie.

Using a Public key infrastruction in which the registration of a key involves proper binding ensures that the public key is bound to the individual to which it is assigned in a way that ensures non-repudiation

See http://en.wikipedia.org/wiki/Public_key_infrastructure . If you follow the proper PKI standards, the person or agent who improperly uses the stolen key can be identified and locked out. If the agent is required to use a certificate, the binding gets pretty tight. A clever and quick-moving thief can escape, but they leave more crumbs.