Protezione di un'API REST multi-database e multi-database

17

Sto cercando di migliorare la sicurezza di un'API REST esistente a cui si accede tramite SSL. Il servizio web è multi-tenant, in modo tale che ogni inquilino abbia un TenantId assegnato.

Il problema che sto affrontando può essere riassunto come:

  1. Come posso determinare l'inquilino?
  2. Come posso determinare se il cliente è legittimo?
  3. La sicurezza basata su cookie HTTP è adatta all'attività o dovrei prendere in considerazione il token?

Attualmente

Attualmente emettiamo manualmente (cioè fuori processo - al telefono, ecc.) una chiave API per ogni client, che includono come intestazione HTTP in ogni richiesta. Questa chiave API si associa a un TenantId. Quando il client invia una richiesta di accesso all'API REST, determiniamo il TenantId, che a sua volta ci consente di verificare il nome utente / password nel database dei titolari corretto. Una volta successo, emettiamo un cookie HTTP limitato nel tempo. Tale cookie viene quindi utilizzato nelle richieste REST successive. Internamente, quel cookie è collegato a una sessione e la sessione contiene informazioni sul profilo utente per ridurre il carico db.

Siamo consapevoli che questo ha alcuni rischi intrinseci per la sicurezza. La chiave API potrebbe essere facilmente estratta dal codice sorgente del client smontato. Intendiamo anche costruire il nostro cliente come una SPA in JavaScript che sia leggibile da chiunque. Sebbene possiamo revocare / cambiare le chiavi, sto cercando un'implementazione standardizzata più sicura.

Alternativa

A quanto ho capito, potrei utilizzare un'alternativa basata su token ai cookie. HMAC è un meccanismo di autenticazione comune per le applicazioni Web, ma ciò richiede la memorizzazione di un segreto condiviso nel client e nel server. Questo segreto sembra avere lo stesso problema della chiave API sopra; in quanto può essere trapelato.

Ho letto anche un po 'di JWT, che sembrano estendere il concetto HMAC in che il server possa persistere i dati di "sessione" dell'utente nel token, riducendo il numero di chiamate al database per le informazioni utente / profilo. Il token JWT viene utilizzato come risultato di un accesso utente / password riuscito. Quindi non c'è nessun problema segreto condiviso qui corretto?

Ho anche letto un po 'di OAuth2, in particolare la concessione di credenziali per password del proprietario di risorse . Non sono nemmeno sicuro se OAuth2 risolva il mio problema.

Determinazione dell'inquilino

Il primo passo è determinare l'inquilino. Piuttosto che usare la chiave API per mappare su TenantId, potrei:

  1. Richiedi il TenantId come parte della richiesta di accesso
  2. Utilizza una mappatura del sottodominio per mappare su TenantId

Convalida del chiamante dell'applicazione

In secondo luogo, devo determinare se una determinata applicazione client è autorizzata ad accedere all'API REST. Da parte mia, sto bene e veramente senza idee brillanti. È quello in cui OAuth2 viene in soccorso?

L'unico modo in cui posso pensare di risolvere questo problema è di rilasciare l'applicazione chiamante con una chiave API temporanea in scadenza dopo che l'utente ha effettuato l'accesso. Anche se non garantisce che l'applicazione non sia canaglia, riduce il rischio a un utente malintenzionato che ha anche ottenuto l'accesso alle credenziali di un utente.

La mia attuale soluzione per cookie HTTP è accettabile? Devo invece passare a un meccanismo di autenticazione basato su token?

Accolgo con favore qualsiasi consiglio tu possa avere. Sto guadando masse di informazioni e sto cercando di capire tutto questo. Qualsiasi consiglio sarebbe felicemente ricevuto!

    
posta Rebecca 23.01.2015 - 15:27
fonte

3 risposte

5

Dovresti guardare a oauth 2.0 (RFC 6749) che ha un numero di flussi che potrebbero soddisfare le tue esigenze.

Per prima cosa devi sapere se i clienti sono pubblici o confidenziali. L'emissione di chiavi API client come si sta facendo è inutile se i client sono browser Web o app scaricati su dispositivi mobili poiché il segreto non può essere mantenuto. Se sono server, le chiavi API sono buone. Quindi questa è la tua prima considerazione. La sezione 2.1 di rfc tratta i tipi di client e determina quali flussi sono applicabili.

È necessario separare l'identificazione del servizio client dall'utente per il quale il cliente sta agendo. Il tuo database di back-end dovrebbe avere un'associazione di utenti con titolari e possibilmente chiavi API con utenti o utente + titolare se si desidera raggiungere un solo tenancy. Ho implementato servizi in cui gli utenti possono partecipare a più inquilini in modo che possano o meno essere applicabili al tuo caso. Ho utilizzato con successo la richiesta di concessione delle credenziali per le password del proprietario della risorsa in modo che un utente possa fornire il proprio nome utente e password da un browser web. Sembra che tu abbia usato un metodo fuori banda per autorizzare il cliente in modo che le credenziali dell'utente non siano richieste. Ma se il client è un browser web o un'app mobile non puoi fare affidamento sull'autent client e devi ottenere l'autorizzazione dell'utente e ciò significa fornire le credenziali dell'utente.

Indipendentemente dal flusso che usi, finisci con una risposta come segue:

HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache

{
    "access_token":"2YotnFZFEjr1zCsicMWpAA",
    "token_type":"example",
    "expires_in":3600,
    "refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
    "example_parameter":"example_value"
} 

Il token di accesso restituito è ciò che il client utilizza nelle sue richieste in modo che possa provare al server che le sue richieste sono autorizzate.

Hai due opzioni per l'intestazione Authorization, 'bearer' o 'mac'.

Authorization: Bearer xxxxxx

Se i tuoi clienti utilizzano TLS, i token bearer rappresentano la via più semplice. Vedi la sezione 7.1 della RFC per maggiori dettagli.

Finché i token di accesso sono solo temporanei, i client possono utilizzare il token di aggiornamento per richiedere un nuovo token di accesso una volta che il token di accesso si avvicina o supera la sua scadenza. Sta a te se vuoi usare i token di aggiornamento o meno. I client dovranno archiviarli in modo sicuro almeno allo stesso livello di protezione che usano per le loro chiavi API. Nel tuo sistema i token di aggiornamento potrebbero non essere necessari per le interazioni server-server se la durata di accesso è sufficiente e l'autenticazione dell'utente non è richiesta. Se è richiesta l'autenticazione dell'utente, i token di aggiornamento possono essere utili se la memoria del client fornisce un livello di protezione sufficiente.

    
risposta data 24.01.2015 - 09:49
fonte
0

Penso che quello che hai in questo momento va bene per quanto riguarda l'identificazione di un inquilino: ogni client avrà bisogno di un identificatore un po ', una chiave API è valida come qualsiasi. Dato che tutto gira su SSL, non devi preoccuparti che venga esposto (almeno durante il transito).

Sembra che tu ti stia preoccupando dell'archiviazione lato client della chiave API, tuttavia, in definitiva, questo non è il tuo lavoro. È responsabilità del cliente mantenere le proprie informazioni private al sicuro (non è compito della banca mantenere il PIN al sicuro). Il tuo compito è proteggere il server e i tuoi clienti da un uso improprio. Un modo per farlo è avere la possibilità di revocare / bloccare una chiave API e / o una sessione.

L'argomento cookie vs HMAC potrebbe non essere così importante come pensi. Chiediti cosa cambia se passi da un cookie a un token? Un HMAC è sicuramente più sicuro dato che è firmato, tuttavia, si potrebbe facilmente criptare il contenuto del cookie. Alla fine ti darà ancora lo stesso mal di memoria che il cookie fa. La parte importante su cui concentrarsi è quanto danno potrebbe fare qualcuno se riescono ad accedervi? Ciò ti porterà a pensare a A. quanto deve essere sicuro il cookie / token e B. come puoi proteggere il server / client se dovesse cadere in mani dannose.

Se devi anche gestire l'autorizzazione del client , probabilmente dovresti guardare OAuth, dato che è esattamente ciò per cui è stato progettato.

    
risposta data 24.01.2015 - 11:05
fonte
0

un'alternativa è usare le chiavi public-private.

  1. l'app client (ad esempio angularjs) avrà la chiave pubblica del server (ad esempio web api)

  2. utilizzando la chiave pubblica del server, il client deve crittografare le credenziali dell'utente (ad es. nome utente, password hash, ecc.). il token generato verrà inviato al server; o per intestazioni o querystamp

  3. il server decodifica il token, ottiene il nome utente e la password hash. quindi ottenere il nome utente persistente + password hash dal database. l'autenticazione è verificando se entrambe le password con hash corrispondono (una dal token e una dal database).

in questa alternativa, la password dell'utente non viene inviata come testo normale. è crittografato / hash prima di essere inviato. il client può memorizzare quel token nella directory locale (browser) o generare un nuovo token ogni volta che chiama il server.

    
risposta data 24.08.2017 - 05:23
fonte

Leggi altre domande sui tag