2013-01-14 8 views
5

Ho creato una semplice API RESTful per un progetto che segue parzialmente this very good blog post by Riyad Kalla. Ora ho letto dozzine di domande simili su Stack Overflow ma non riesco a trovare una risposta alla mia domanda di sicurezza.Protezione di un endpoint RESTful dell'API senza sessione

In breve, le mie richieste andare in questo modo:

  1. Il cliente ha una chiave API pubblica (testo in chiaro, accessibili a chiunque sniffing del traffico di rete o il corretto controllo del codice sorgente)
  2. il client invia una richiesta al server con la chiave API pubblica
  3. Il server ha una chiave API segreta (riservata a chiunque tranne lo sviluppatore)
  4. Il server crea un hash HMAC-SHA1 composto dai dati della richiesta del client e dalla chiave API segreta
  5. Il server invia una richiesta identica alla richiesta del client al server API, ma compresa la risultante HMAC-SHA1
  6. Il server API cerca la chiave API segreta nel suo database in base alla chiave API pubblica che riceve
  7. il server API ricrea un hash HMAC-SHA1 utilizzando gli stessi dati del server dello sviluppatore
  8. Se gli hash corrispondono, la richiesta viene considerato valido e viene elaborato normalmente

sono preoccupato che qualcuno usando il mio servizio potrebbe recuperare la chiave API pubblica (sniffando il traffico di rete diciamo), e quindi semplicemente cURL il sam e richiede che il client faccia originariamente tramite il browser utilizzando AJAX direttamente al server dello sviluppatore. Pertanto, l'utente malintenzionato potrebbe essere autenticato come utente legittimo e accedere all'API con un'altra chiave API segreta.

Proverò a dare un esempio concreto. Normalmente lo farei:

  1. AJAX a ottenere una richiesta al mio server.
  2. Il mio server esegue l'hashing della mia richiesta con il mio segreto API e lo invia al server API.
  3. Il server API convalida la mia richiesta e restituisce il carico utile.

Ma ho paura che:

  1. Dr. Evil sarà annusare la mia chiave API pubblica.
  2. Dr. Evil cercherà di ottenere una richiesta al mio server usando la mia chiave API pubblica.
  3. Il mio server rifiuterà la richiesta del Dr. Evil con la mia API segreta e la invierà al server API.
  4. Il server API convalida e restituisce il carico utile per completare i piani viziosi del Dr. Evil.
  5. Dr. Evil ride una risata malvagia.

Qualcosa che mi manca o è solo una parte del gioco RESTful API?

AGGIORNAMENTO: Sto volontariamente omettendo qualsiasi forma di convalida del timestamp per mantenere le cose semplici e concentrarsi solo sul problema di autenticazione.

UPDATE 2: Ho aggiunto una convalida $_SERVER['HTTP_REFERER'] al processo. L'obiettivo qui è che il client deve inviare un referrer insieme alla richiesta e deve corrispondere al referrer elencato nel database sul lato dell'API. Sfortunatamente, i referrer HTTP possono essere falsificati facilmente. È ancora un altro livello di sicurezza, ma non è ancora perfetto.

UPDATE 3: Ho modificato il mio codice lato server per impostare il referrer sull'indirizzo IP remoto. Ciò impone che ogni richiesta inviata al mio server che vuole essere sottoposta a hash usando la chiave API segreta arrivi in ​​definitiva al server API con l'indirizzo IP della richiesta originale. Questo IP può quindi essere convalidato e la richiesta può essere inoltrata. Credo che sia ancora possibile simulare lo $_SERVER['REMOTE_ADDR'], ma è più complesso di fingere $_SERVER['HTTP_REFERER'] ... Ancora non è perfetto, immagino.

UPDATE 4: Secondo questi post: How to fake $_SERVER['REMOTE_ADDR'] variable? e https://serverfault.com/questions/90725/are-ip-addresses-trivial-to-forge, falsificare la $_SERVER['REMOTE_ADDR'] è possibile però difficile. Tuttavia, è impossibile ricevere una risposta dalla richiesta simulata poiché non si ha il controllo della rete simulata. La richiesta può essere validata con successo ma la sua risposta non cadrà in mani dannose.

risposta

0

La soluzione che ho trovato per fermare altri script di utilizzare una chiave API pubblica e l'invio di richieste allo script HMAC-hashing lato server è inviare l'identità del richiedente originale insieme alla richiesta. Sto usando $_SERVER['REMOTE_ADDR'] per determinare l'identità del richiedente originale dal momento che è più difficile da falsificare, e fingere di solito significa che non otterranno una risposta.

/* $this as a class that handles requests */ 

// Build hash and include timestamp 
$this->vars['timestamp'] = time(); 
$this->vars['hash'] = hash_hmac('sha1', http_build_query($this->vars).$this->vars['token'], API_SECRET); 

// Send request to API 
curl_setopt_array($this->curl, array(
    CURLOPT_RETURNTRANSFER => 1, 
    CURLOPT_URL => $url, 
    CURLOPT_POST => $this->method == 'post' ? 1 : NULL, 
    CURLOPT_POSTFIELDS => $this->method == 'post' ? $this->vars : NULL, 
    CURLOPT_CONNECTTIMEOUT => 15, 
    CURLOPT_TIMEOUT => 15, 
    CURLOPT_REFERER => $_SERVER['REMOTE_ADDR'], // Referer here! 
    CURLOPT_MAXREDIRS => 3, 
    CURLOPT_HTTPGET => $this->method == 'get' ? true : false 
)); 

Una volta inviato, l'API non solo controllare la chiave API segreta dal database, ma verifica anche se il $_SERVER['HTTP_REFERER'] è elencato come consentito! Ciò consente inoltre all'API di accettare server per utente.

4

Sei sulla strada giusta utilizzando HMAC. Tuttavia, ci sono altre due cose che renderanno la tua applicazione più sicura.

  1. Richiedere un timestamp nel POST client, deve essere convalidato entro 5 minuti dall'ora del server. Dovrebbe essere incluso anche nella generazione di HMAC. Se qualcuno tenta di cambiarlo, la firma HMAC non sarà valida, a meno che non abbia la chiave segreta per aggiornare la firma HMAC.
  2. Utilizzare SSL, con convalida del certificato. Previene un uomo nel mezzo dell'attacco. Non consentire richieste non ssl.
+0

Grazie. Ho volontariamente escluso la parte timestamp per mantenere le cose semplici in quanto non è un grosso problema da implementare nel mio codice attuale, avrei dovuto accennare a ciò. Non sono sicuro di aver capito correttamente la funzione SSL. È impossibile sniffare il traffico? L'utente malintenzionato può ancora rubarlo dal codice sorgente JavaScript, no? Mi manca sicuramente qualcosa qui ... –

+0

SSL è la crittografia del trasporto. Rende molto più difficile sniffare. Anche con le API questa è una buona idea. – datasage

+0

Ma ho ancora lo stesso problema se l'utente malintenzionato può ottenere la chiave API pubblica dall'origine, giusto? –

Problemi correlati