Questa metodologia di firma è sicura?

1

Sto lavorando all'autenticazione per il mio JSON-RPC API e la mia strategia di lavoro corrente utilizza le richieste firmate inviate tramite POST a SSL .

Mi chiedo se qualcuno possa vedere eventuali vulnerabilità che non ho preso in considerazione con il seguente metodo di firma.

Tutte le comunicazioni tra il client e il server avvengono tramite% richieste diPOST inviate su SSL . Le richieste http non sicure sono negate a titolo definitivo dal server API.

Dipendenze

var uuid = require('node-uuid');
var crypto = require('crypto');
var moment = require('moment');
var MyAPI = require('request-json').newClient('https://api.myappdomain.com');

Vars

var apiVersion = '1.0';
var publicKey = 'MY_PUBLIC_KEY_UUID';
var secretKey = 'MY_SECRET_KEY_UUID';

Richiedi oggetto

var request = {
    requestID : uuid.v4(),
    apiVersion : apiVersion,
    nonce : uuid.v4(),
    timestamp : moment.utc( new Date() ),
    params : params
}

Firma

var signature = crypto.createHmac('sha512',secretKey).update(JSON.stringify(request)).digest('hex');

Pacchetto di payload (inviato come testo in chiaro tramite POST su TLS)

var payload = {
    request: request,
    publicKey : publicKey,
    signature : signature
}

Richiesta POST

MyAPI.post('/', payload, function(error, response, body){
    console.log(result);
});

Payload risultante

{
  "request" : {
    "requestID" : "687de6b4-bb02-4d2c-8d3a-adeacd2d183e",
    "apiVersion" : "1.0",
    "nonce" : "eb7e4171-9e23-408a-aa2b-cd437a78af22",
    "timestamp" : "2014-05-23T01:36:52.225Z",
    "params" : {
      "class" : "User"
      "method" : "getProfile",
      "data" : {
        "id" : "SOME_USER_ID"
      }
    }
  },
  "publicKey" : "PUBLIC_KEY",
  "signature" : "7e0a06b560220c24f8eefda1fda792e428abb0057998d5925cf77563a20ec7b645dacdf96da3fc57e1918950719a7da70a042b44eb27eabc889adef95ea994d1",
}

sul lato server

E quindi sul lato server si verifica quanto segue per autenticare la richiesta:

  1. PUBLIC_KEY viene utilizzato per cercare SECRET_KEY nel DB.
  2. SECRET_KEY viene utilizzato per creare un HMAC dell'oggetto request dal payload.
  3. L'hash inviato nel payload viene confrontato con l'hash creato sul server. Se corrispondono, PUBLIC_KEY è autenticato.
  4. Il timestamp viene valutato e l'autenticazione viene rifiutata se la richiesta è troppo vecchia, altrimenti il timestamp viene autenticato.

Per quanto ho capito, questo è un metodo sicuro per la firma e le richieste di autenticazione inviate su SSL . È corretto?

Grazie in anticipo per qualsiasi aiuto.

    
posta AJB 23.05.2014 - 04:07
fonte

1 risposta

1

Una delle domande che potresti prendere in considerazione è il motivo per cui ritieni che le richieste firmate siano necessarie se tutte le API sono solo SSL? SSL fornisce sia tamper & riproduci la protezione, quindi a meno che tu non abbia altri dubbi, questo potrebbe essere ridondante.

Anche se prevedi di usare SSL ovunque, il che è fantastico! I miei commenti seguenti esplorano la possibilità che non ci sia SSL in uso.

1 - URL e amp; Verbale HTTP non firmato

Nell'esempio sopra riportato, la destinazione prevista del payload non è inclusa nella firma del payload. Considerare se il carico utile potrebbe essere catturato, potrebbe essere reindirizzato in un'altra posizione indesiderata. Forse una richiesta che deve essere inviata a / users / 123 viene instradata a / users / 456, oppure una richiesta inviata a "v1.api.mysite.com" viene inviata a "v2.api.mysite.com" o a un POST è cambiato in PATCH.

2 - Supporto per il keyrolling

Questo potrebbe essere al di fuori della portata della tua domanda, ma non vedo alcun supporto per la rotazione della chiave di firma senza la possibilità di impatto sul cliente. Sarebbe vantaggioso se il tuo servizio potesse mantenere due segreti autorizzati per un determinato ID pubblico. In questo modo la chiave potrebbe essere ruotata regolarmente (per esempio con molta prudenza) senza una stretta coordinazione tra client & servizio.

3 - Firma di 'Agilità'

Che cosa succede alla tua applicazione se viene rilevata una nuova debolezza in SHA2 o nella costruzione attuale di HMAC? Cosa succede se hai un cliente che preferisce usare ECDSA su HMAC? Considera di avere un numero di versione o un identificatore 'schema' della firma come parte del carico utile firmato. In questo modo il tuo servizio può capire quale approccio ha utilizzato il client per firmare il payload.

4 - Troppo vecchio

Nel tuo post hai menzionato che il servizio può rifiutare richieste troppo vecchie (per mitigare gli attacchi di replay). Cosa succede se il cliente non è d'accordo con la tua definizione di troppo vecchio? Considera di consentire al client di specificare quanti anni ha troppo vecchio nel payload firmato. Di nuovo, questo non è tanto un punto debole nel tuo approccio alla generazione di firme, più un commento sul protocollo in generale.

5 - Altri Lits

  • Il campo 'nonce' sembra ridondante. Hai già un GUID casuale che serve come ID di richiesta, a meno che il tuo servizio non richieda il nonce, questo può essere rimosso in modo sicuro.

  • A seconda del tuo parser JSON (& how / when deseralize), questo potrebbe non prendere tutte le modifiche al tuo payload. Ad esempio, se modifico il payload per uscire da un personaggio che non richiede l'escape, il risultato è semanticamente equivalente. Poiché stai desertificando il JSON prima di verificare se è stato modificato, potresti essere vulnerabile agli attacchi che cercano di sfruttare il tuo deseralizzatore o attacchi mirati a bug sottili su come vengono gestiti i caratteri di escape.

Ma infine, ripeto ciò che ho detto prima - la firma della tua richiesta potrebbe essere ridondante quando supporti solo SSL come trasporto. Semplicemente autenticando il tuo chiamante potrebbe essere sufficiente.

    
risposta data 24.05.2014 - 18:18
fonte

Leggi altre domande sui tag