Protezione dell'API REST: la firma api_secret e ssl è sufficiente?

10

per proteggere un'API RESTful ho pensato alla seguente procedura di autenticazione per ogni chiamata:

  • Tutti i dati sono crittografati tramite SSL
  • Ogni richiesta HTTP effettuata dal client avrà una firma come sha512(keysort(POSTDATA.push({"secret": API_SECRET, "timestamp": utc_time()}))
  • Il server conosce anche i client API_SECRET e controlla se la firma corrisponde a quella inviata dal client. In tal caso, la richiesta è legittima e verrà elaborata.

Il problema che sto affrontando qui è il seguente - Poiché l'API verrà chiamata da un'app per iPhone e una WebApp, non riesco a pensare a un modo di non che trasmette l'API_SECRET una volta . Quindi diciamo che l'utente effettua l'accesso, invia username = john & password = doe (SSL crittografato) e riceve un API_SECRET in risposta dal server. Questo API_SECRET verrà quindi memorizzato dal client e utilizzato per firmare tutte le ulteriori chiamate API.

Sto utilizzando la firma per ridurre il rischio di attacchi MITM, ma se trasferisco la chiave una volta sembra un problema, ma non riesco a pensare a un modo per risolverlo.

Grazie per il tuo aiuto!

    
posta doque 13.08.2012 - 14:30
fonte

2 risposte

7

Hrm. In cima all'SSL non sono sicuro di quello che stai ricevendo da API_SECRET qui.

Penserei che avere un certificato SSL del server da una fonte conosciuta e attendibile sarebbe il meglio che si possa fare qui, assumendo che l'app client sia distribuita in maniera attendibile. A quel punto, il client può verificare l'autenticazione del server tramite la sessione SSL e il server autentica il client con nome utente / password.

Come dice @Polynomial - SSL dovrebbe crittografare la sessione in modo tale che gli attacchi MITM tra gli endpoint SSL non costituiscano un problema. Trick è sapere dove si trovano questi endpoint e essere sicuri che si trovano nella tua infrastruttura in una posizione ben congegnata. Ad esempio, se esiste un endpoint SSL davanti al server delle app: cosa protegge quell'ultimo miglio di trasmissione?

Allo stesso modo - l'applicazione (mobile o web) controlla correttamente che il certificato SSL del server provenga da una fonte attendibile?

Aggiunta per domanda nel commento:

Ho dato un'occhiata al riferimento di classe per NSURLRiferimento sulle pagine di sviluppo Mac e non ho trovato alcun riferimento a SSL affatto ... infatti i commenti dicono che è indipendente dal protocollo, il che ha senso dato che si chiama URL richiesta.

Non penso che tu possa presumere che tu abbia anche HTTPS con questa classe - devi fare qualcosa per configurare la sessione HTTPS invece di eseguire l'impostazione predefinita su HTTP. Ecco la panoramica sugli sviluppatori Mac su SSL . Mi disturba un po ', perché non esiste una funzione ovvia per ottenere il certificato del server

.

Quindi avrai bisogno anche del Certificato, chiave e affidabilità servizi - per verificare il certificato.

NON darei per scontato che l'ambiente di sviluppo di Apple farà semplicemente questo per te. L'esperienza precedente con altre API non mi ha dato alcun motivo per fidarmi di questo e non vedo la documentazione che dice quello che fa esplicitamente. Non sono nemmeno particolarmente sicuro di come gli store trust lavorino in questo ambiente di sviluppo. E questo non è un posto dove vuoi fare ipotesi cieche. Analizzerei le condizioni in cui l'ambiente forza SSL, verifica l'autenticità dei certificati del server e verifica che il certificato sia firmato da una CA attendibile. Se non disponi della documentazione che ti dice quando e come accadono queste cose, non puoi davvero supporre che il tuo servizio sia sicuro.

    
risposta data 13.08.2012 - 23:32
fonte
9

Qui ci vengono poste due domande diverse: sul metodo per generare una "firma" in ogni richiesta e sul metodo per il provisioning di API_SECRET ai client al primo utilizzo. A rigor di termini, questi dovrebbero essere stati suddivisi in due domande, ma risponderò a entrambi.

Il tuo formato di firma. hai il concetto di base su giusto, ma ho alcuni suggerimenti / critiche costruttive:

  • Utilizza un MAC. Dovresti utilizzare un codice di autenticazione del messaggio, non un hash. L'utilizzo di un hash, come hai fatto, è vulnerabile agli attacchi di estensione della lunghezza . Ad esempio, potresti usare MAC (K, D) dove K è il tuo API_SECRET , D sono i dati della richiesta e il timestamp, e MAC è un algoritmo di codice di autenticazione dei messaggi sicuro. AES-CMAC è una buona scelta di algoritmo MAC. SHA1-HMAC è un'altra scelta standard.

  • Includi il timestamp nella richiesta. Probabilmente dovrai includere il timestamp nella richiesta. Il server deve conoscere il timestamp utilizzato dal client, per convalidare la richiesta. Dal momento che non puoi fare affidamento sugli orologi del client e del server per essere perfettamente sincronizzati, devi inviare il timestamp nella richiesta.

  • Fai attenzione ai parametri duplicati. se hai due parametri di richiesta con la stessa chiave, puoi eseguire attacchi di tipo host-pollution pollution (HPP). Suggerisco di verificare che le chiavi siano tutte univoche e che la richiesta non abbia alcun parametro con una chiave di secret o timestamp (se si aggiungeranno quei parametri ai parametri POST).

  • Attenzione ai problemi di concatenazione. Non hai detto come prendi l'elenco ordinato dei parametri e li trasformi in una stringa. I dettagli contano. Se si concatenano tutti i valori, si sarà vulnerabili, poiché il confine tra i campi è ambiguo. Quindi, non utilizzare la concatenazione; utilizza una codifica non decifrabile in modo durante la preparazione dei dati per l'hashing (o la firma da parte del MAC).

  • Altre risorse. Vedi anche Come implementare un meccanismo chiave dell'API per una domanda correlata.

Fornitura di segreti crittografici. Quindi, è necessario un modo per ottenere API_SECRET per ciascun client. Ecco un modo standard per farlo. Al primo accesso, l'utente digita la password nel client. Il client apre una connessione SSL al server e invia nome utente e password dell'utente. Il server convalida le credenziali dell'utente e, se sono corrette, invia il valore API_SECRET di questo utente al client. Il client ora memorizza il API_SECRET nella memoria privata (ma non memorizza la password dell'utente). Nelle connessioni successive, il client può ora utilizzare il suo API_SECRET per autenticarsi.

Un approccio alternativo. Se vuoi collegarti solo da client dedicati (ad esempio, un'app mobile, un'applicazione desktop, ma non da Javascript in esecuzione nel browser), potresti prendere in considerazione la seguente alternativa. Invece di utilizzare la crittografia a chiave simmetrica, utilizzare la crittografia a chiave pubblica. In altre parole, invece di utilizzare API_SECRET , ogni client deve generare il proprio certificato client SSL. Il client memorizza la chiave privata in modo sicuro. Alla prima connessione, il client esegue l'autenticazione utilizzando la password dell'utente e invia la sua chiave pubblica (in realtà, il suo cert), quindi dimentica la password dell'utente. Il server memorizza il certificato del cliente e tutte le connessioni successive vengono autenticate utilizzando SSL con certificati client.

Questo è un approccio strong. Si prende cura di tutti i potenziali approcci di sicurezza sopra elencati. L'unico svantaggio è che non è possibile scrivere facilmente un client Javascript / AJAX eseguito nel browser.

    
risposta data 15.08.2012 - 04:06
fonte

Leggi altre domande sui tag