Come posso proteggere le chiamate API REST?


91

Sto sviluppando l'app Web riposante che utilizza alcuni framework Web popolari sul backend, ad esempio (rails, sinatra, flask, express.js). Idealmente, voglio sviluppare il lato client con Backbone.js. Come faccio a consentire solo al mio lato client javascript di interagire con quelle chiamate API? Non voglio che quelle chiamate API siano pubbliche e vengano chiamate dacurl o semplicemente inserendo il collegamento nel browser.


Tutte le chiamate API richiedono un token che viene passato al client quando la pagina viene pubblicata?
hajpoj


L'SDK javascript di Amazon AWS utilizza l'URL dell'oggetto pre-firmato: - docs.aws.amazon.com/AmazonS3/latest/dev/…
rjha94

Risposte:


90

Come primo principio, se la tua API viene utilizzata dal tuo client JS, devi presumere che sia pubblica: un semplice debugger JS mette un attaccante in una posizione in cui può inviare una richiesta identica byte per byte da un strumento di sua scelta.

Detto questo, se leggo correttamente la tua domanda, questo non è ciò che vuoi evitare: quello che davvero non vuoi che accada è che la tua API viene consumata (su base regolare) senza che il tuo client JS sia coinvolto. Ecco alcune idee su come se non imporre, quindi almeno incoraggiare a utilizzare il tuo cliente:

  • Sono sicuro che la tua API abbia una sorta di campo di autenticazione (ad esempio Hash calcolato sul client). In caso contrario, dai un'occhiata a questa domanda SO . Assicurati di utilizzare un salt (o anche una chiave API) che viene fornito al tuo client JS su base di sessione (aot hardcoded). In questo modo, un consumatore non autorizzato della tua API è costretto a lavorare molto di più.

  • Durante il caricamento del client JS, ricorda alcune intestazioni HTTP (mi viene in mente lo user agent) e l'indirizzo IP e chiedi la riautenticazione se cambiano, utilizzando le blacklist per i soliti sospetti. Ciò costringe un aggressore a fare di nuovo i compiti in modo più approfondito.

  • Sul lato server, ricorda le ultime chiamate API e prima di consentirne un'altra, controlla se la logica aziendale consente quella nuova in questo momento: questo nega a un utente malintenzionato la capacità di concentrare molte delle sue sessioni in una sessione con il tuo server: in combinazione con le altre misure, questo renderà facilmente individuabile un aggressore.

Potrei non averlo detto con la necessaria chiarezza: considero impossibile rendere completamente impossibile per un maltrattante consumare il tuo servizio, ma puoi renderlo così difficile, potrebbe non valerne la pena.


questa è un'informazione utile, ma cosa succede se voglio fare un po 'di autenticazione dalla mia API di backend a un'altra app API come un server separato, per semplificare la mia domanda, voglio che il mio back-end aka node.js invii la richiesta di recupero a un altro back- server finale che è il mio, per alcuni motivi è necessario, ma voglio proteggere le chiamate api, poiché può accedere ai dati sensibili e non posso usare sesions o jwt perché non posso memorizzarli effettivamente nel browser.
La piramide

@ Thepyramid Non importa cosa fa la chiamata API sul lato server, specialmente se il lato server esegue un'altra chiamata API di 2 ° livello. La parte importante è trattare il tuo server non come un proxy, ma come un'applicazione.
Eugen Rieck

puoi spiegarci di più come fare come domanda non come proxy
La piramide

1
Quello che intendo è: per ottenere una discreta quantità di sicurezza è necessario utilizzare tutti gli strumenti di cui dispone una webapp: sessioni, un database di autenticazione, una logica di business. Se non lo fai e tratti il ​​tuo server come un modo per passare le richieste a un altro server, lo stai semplicemente usando come proxy per quell'altro server e sei limitato dalla sicurezza offerta da quell'altro server.
Eugen Rieck

1
@PirateApp Un utente malintenzionato può facilmente ignorare le intestazioni CSRF. Funzionano solo se il dispositivo finale è un browser senza patch
Eugen Rieck

12

Dovresti implementare una sorta di sistema di autenticazione. Un buon modo per gestirlo è definire alcune variabili di intestazione previste. Ad esempio, puoi avere una chiamata API di autenticazione / accesso che restituisce un token di sessione. Le chiamate successive alla tua API si aspetteranno che un token di sessione venga impostato in una variabile di intestazione HTTP con un nome specifico come "your-api-token".

In alternativa, molti sistemi creano token di accesso o chiavi che sono previsti (come youtube, facebook o twitter) utilizzando una sorta di sistema di account API. In questi casi, il tuo cliente dovrebbe memorizzarli in qualche modo nel client.

Quindi è semplicemente una questione di aggiungere un controllo per la sessione nel tuo framework REST e lanciare un'eccezione. Se possibile, il codice di stato (per essere riposante) sarebbe un errore 401.


8
Anche se nulla impedisce loro di guardare le intestazioni e riprodurle.
cdmckay

1
@cdmckay: un token deve corrispondere a un token archiviato in una sessione. La semplice riproduzione dell'intestazione comporterà la risposta "Non autorizzato" se proviene da una sessione diversa.
Andrei Volgin

3
Possono comunque utilizzare la stessa sessione e modificare le richieste prima che vengano inviate all'API ... o anche utilizzando la console in fase di esecuzione generare una chiamata con intestazioni / campi corrispondenti modificando solo le parti di cui hai bisogno ...
Potter Rafed

2
@PotterRafed: se un utente accede alla propria sessione valida, viene chiamata utilizzando un'app, non attaccandola. Lo scopo dell'autenticazione è impedire l'accesso a sessioni / dati di altri utenti .
Andrei Volgin,

@AndreiVolgin sì, abbastanza giusto, ma è ancora una vulnerabilità
Potter Rafed

9

Esiste uno standard aperto ora chiamato "JSON Web Token",

vedere https://jwt.io/ & https://en.wikipedia.org/wiki/JSON_Web_Token

JSON Web Token (JWT) è uno standard aperto basato su JSON (RFC 7519) per la creazione di token che affermano un certo numero di attestazioni. Ad esempio, un server potrebbe generare un token con la dichiarazione "accesso come amministratore" e fornirlo a un client. Il client potrebbe quindi utilizzare quel token per dimostrare di aver effettuato l'accesso come amministratore. I token sono firmati dalla chiave del server, quindi il server è in grado di verificare che il token sia legittimo. I token sono progettati per essere compatti, sicuri per gli URL e utilizzabili soprattutto nel contesto SSO (Single Sign-On) del browser web. Le attestazioni JWT possono essere generalmente utilizzate per trasferire l'identità degli utenti autenticati tra un provider di identità e un provider di servizi, o qualsiasi altro tipo di attestazioni come richiesto dai processi aziendali. [1] [2] I token possono anche essere autenticati e crittografati. [3] [4]


Cosa impedirebbe a un utente di copiare il proprio token e utilizzarlo in qualsiasi altra risposta?
Ulad Kasach

1
@UladKasach ad essere sincero non li ho mai approfonditi, ma afaik sono scadenti, unici per il tuo utente e crittografati da SSL (che stai ovviamente praticando), è esattamente la stessa idea dietro oauth
afaik

3

Mi scusi @MarkAmery ed Eugene, ma non è corretto.

La tua app js + html (client) in esecuzione nel browser PU essere configurata per escludere chiamate dirette non autorizzate all'API come segue:

  1. Primo passaggio: configura l'API per richiedere l'autenticazione. Il client deve prima autenticarsi tramite il server (o qualche altro server di sicurezza), ad esempio chiedendo all'utente umano di fornire la password corretta.

Prima dell'autenticazione le chiamate all'API non vengono accettate.

Durante l'autenticazione viene restituito un "token".

Dopo l'autenticazione verranno accettate solo le chiamate API con il "token" di autenticazione.

Ovviamente in questa fase solo gli utenti autorizzati che dispongono della password possono accedere all'API, sebbene se sono programmatori che eseguono il debug dell'app, possono accedervi direttamente a scopo di test.

  1. Secondo passo: ora configura un'API di sicurezza aggiuntiva, che deve essere chiamata entro un breve limite di tempo dopo che l'app client js + html è stata inizialmente richiesta dal server. Questo "callback" dirà al server che il client è stato scaricato con successo. Limita le chiamate API REST in modo che funzionino solo se il client è stato richiesto di recente e con successo.

Ora per poter utilizzare la tua API devono prima scaricare il client ed effettivamente eseguirlo in un browser. Solo dopo aver ricevuto con successo la richiamata e quindi l'immissione dell'utente entro un breve lasso di tempo, l'API accetterà le chiamate.

Quindi non devi preoccuparti che questo possa essere un utente non autorizzato senza credenziali.

(Il titolo della domanda, "Come posso proteggere le chiamate API REST", e dalla maggior parte di ciò che dici, questa è la tua principale preoccupazione, e non la domanda letterale di COME viene chiamata la tua API, ma piuttosto DA CHI, corretta? )


5
Il secondo punto non ha senso. Se un utente malintenzionato deve caricare la tua app, lo farà (il tuo callback è visibile). E poi attaccare.
Andrei Volgin

Il punto 2 è in aggiunta al punto 1. L'autore dell'attacco necessita ancora di autenticazione. Il punto 2 aggiunge solo a ciò la necessità di scaricare effettivamente l'app html per essere autorizzati. Quindi una chiamata direttamente alle API senza l'app (presumibilmente accessibile e scaricata solo dopo l'autenticazione) è impossibile. Qual è qualcosa che è stato richiesto in questa domanda.
pashute

Puoi semplicemente consentire solo le richieste dal tuo dominio.
Andrei Volgin

Ciò limita solo le chiamate all'interno del dominio, quindi ora gli utenti dell'app browser javascript devono trovarsi all'interno del dominio (probabilmente non è qualcosa che volevano knd) e quegli utenti possono ancora chiamare l'API direttamente tramite curl.
pashute

2
Quello che sembri trascurare è che QUALSIASI cosa chiedi di fare al browser dell'utente, può essere replicata da un utente malintenzionato: per farlo fare al browser, deve essere leggibile.
Eugen Rieck

1
  1. Imposta una SESSION var sul server quando il client carica per la prima volta il tuo index.html(o backbone.jsecc.)

  2. Controlla questa variabile sul lato server su ogni chiamata API.

PS questa non è una soluzione di "sicurezza" !!! Questo è solo per facilitare il carico sul tuo server in modo che le persone non ne abusino o "colleghino" la tua API da altri siti web e app.


0

Ecco cosa faccio:

  1. Proteggi l'API con un'intestazione HTTP con chiamate come X-APITOKEN:

  2. Usa le variabili di sessione in PHP. Disporre di un sistema di accesso e salvare il token utente nelle variabili di sessione.

  3. Chiama il codice JS con Ajax in PHP e usa la variabile di sessione con curl per chiamare l'API. In questo modo, se la variabile di sessione non è impostata, non chiamerà e il codice PHP contiene il token di accesso all'API.

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.