Il tempo costante si confronta quando le dimensioni dell'array non sono uguali?

1

Qual è il modo preferito o consigliato per perseguire il tempo del concorrente quando le lunghezze dell'array non sono uguali?

Dovremmo uscire il prima possibile? Qualcosa come:

if (array1.size() != array2.size()) {
    return NOT_EQUAL;
}

int accum = 0;
for(int i = 0; i < array1.size(); i++) {
    accum |= array1[i] ^ array2[i];
}

return (accum == 0) ? EQUAL : NOT_EQUAL;

O dovremmo evitare l'uscita anticipata e confrontare il più possibile nella speranza di mascherare il più possibile? Qualcosa come:

int size = min(array1.size(), array2.size());
int accum = (array1.size() ^ array2.size());

for(int i = 0; i < size; i++) {
    accum |= array1[i] ^ array2[i];
}

return (accum == 0) ? EQUAL : NOT_EQUAL;

O qualcos'altro?

O questa domanda è più appropriata per le persone sul Crypto.SE perché la sua minutia teorica?

EDIT : sembra essere correlato a Intervalli di tempo sugli hash delle password . Ma la domanda citata è una particolare istanza del problema generalizzato (e sono interessato alla domanda generalizzata).

Non sono sicuro di essere d'accordo con la risposta o affermazione della domanda citata che "L'uso di attacchi temporali in questo caso non dirà in alcun modo a un aggressore più di quello che avrebbe se avesse l'hash e il sale memorizzati ... " perché l'utente malintenzionato potrebbe tentare di recuperare la password con hash anche se sincronizza gli attacchi. Data una password hash, è solo un balzo indietro alla password in alcuni casi.

    
posta jww 05.01.2015 - 01:15
fonte

3 risposte

1

Abortire in anticipo va bene, poiché non rivela i tempi per qualcosa di segreto (a meno che tu non consideri la lunghezza un segreto, il che non sembra plausibile).

Come per la tua modifica, anche il confronto degli hash delle password in un tempo non costante va bene. L'attaccante non ha un meccanismo efficiente per "scegliere" le uscite hash della password in modo tale da poter scorrere tutte le possibilità di un byte in una posizione mantenendo i byte precedenti costanti. Quindi non c'è di nuovo nessun attacco temporale - nemmeno per rivelare la password hash.

    
risposta data 05.01.2015 - 02:00
fonte
1

Problema: vuoi confrontare due sequenze, una sequenza fornita dall'utente U[] e una sequenza segreta S[] di cui vuoi mantenere segreta la lunghezza. Non vuoi rivelare, attraverso il tempo trascorso del confronto, se S è più corto di U o la lunghezza del prefisso comune di U e S .

Non puoi interrompere il confronto dopo aver raggiunto la fine di S perché ciò rivelerà la lunghezza di S . Né puoi abortire dopo la prima mancata corrispondenza perché ciò rivelerà la lunghezza del prefisso comune. Quello che puoi fare è ripetere l'ultimo elemento in S fino a raggiungere la fine di U . Ad esempio, se U è "goodbye" e S è "hello" , devi confrontare come se fosse "hellooo" .

Il seguente codice (non testato) in Python dovrebbe illustrare il concetto:

def slow_seq_eq(userseq, secretseq):
    """Compare sequences without disclosing secretseq's length."""
    Silast = len(secretseq) - 1
    is_equal = True
    for Uidx in range(len(userseq)):
        Sidx = min(Uidx, Silast)  # Repeat the last element of S to len(U)
        if secretseq[Sidx] != userseq[Uidx]:
            is_equal = False
    if len(U) != len(S):
        is_equal = False
    return is_equal

Questo ovviamente presuppone che l'operatore di confronto != richieda un tempo costante, così come l'operatore di indicizzazione. Disporre di S per essere posizionato in un certo allineamento relativo alle linee di cache o alle pagine di memoria virtuale potrebbe in teoria mantenere vivo l'attacco di temporizzazione.

    
risposta data 06.01.2015 - 02:08
fonte
1

Se i dati su cui stai confrontando non sono un segreto, allora non importa ciò che fai. Gli attacchi a tempo vengono utilizzati per apprendere informazioni a cui non si ha già accesso. Se hai già accesso, l'attacco non è necessario.

Se stai proteggendo un segreto, non importa se si tratta di una password o meno. Dovresti gestirlo allo stesso modo, con le stesse precauzioni. Per evitare i canali laterali di temporizzazione, ci si assicura che la lunghezza dell'input sia uguale alla lunghezza del valore memorizzato eseguendoli entrambi e eseguendo un confronto temporale costante. Naturalmente, è necessario memorizzare il valore hash del valore memorizzato nel database, in modo che non lo si ricalcoli ogni volta. Vedi pseudocodice sotto.

Pseudocodice per confronti a tempo costante:

bool compareToSecret(input/* input from user*/)
  dbHash = getSecretFromDb()

  inHash = hash(input); // sha256, bcrypt or whatever. Attacker 
                        // knows how long this takes, but it 
                        // doesn't get her anything

  // at this point, both inhash and dbhash are the same length.

  // the following loop is constant order time. Hashes are always the
  // same length, and all values of the hashes are always compared
  bool result = true
  int len = strlen(inHash)
  for( int i=0; i<len; i++ )
     result &= (inHash[i] == dbHash[i])

  return result

interruzione anticipata durante il confronto

L'interruzione anticipata durante il confronto è problematica, in quanto fornisce informazioni sul confronto e può essere utilizzata per imparare direttamente la password.

  1. L'attaccante prova i segreti della lunghezza 1. Uno di questi segreti impiegherà più di un millisecondo per tornare rispetto agli altri, dal momento che esiste un segreto di 1 lunghezza il cui primo carattere corrisponde al segreto memorizzato. L'attaccante apprende il primo carattere del segreto.
  2. L'attaccante prova 2 tutti i segreti dei personaggi con la prima lettera che inizia con il valore corretto noto. Uno di questi segreti sarà più veloce di alcuni millisecondi, dal momento che il secondo carattere confronta correttamente.
  3. L'attaccante si ripete, attaccando separatamente ciascun personaggio del segreto. Alla fine, l'attaccante apprende il segreto memorizzato.

Questo è più veloce di un attacco di forza bruta, perché l'attaccante può attaccare ogni personaggio separatamente invece dell'intero segreto in una sola volta.

interruzione anticipata: prima di confrontare

Abortire presto, come menzionato da Steven Tousset, fa trapelare la lunghezza del segreto. All'inizio questo non sembra molto, ma lascia che l'aggressore acceleri il suo attacco di ordini di grandezza. Diciamo che il sistema accetta i segreti della lunghezza 1-5. Mantenendolo molto semplice, il segreto è composto solo da cifre. Quindi, ci sono 10 + 100 + 1.000 + 10.000 + 100.000 = 111,110 valori possibili. Un attacco di forza bruta deve fare circa 100.000 test per provare ogni possibile valore.

Se il sistema consente all'autore dell'attacco di conoscere la lunghezza del segreto, un utente malintenzionato può ridurre drasticamente il numero di valori che è necessario testare prima provando 5 valori: "1", "12", "123", "1234" e "12345". Ora l'attaccante sa per quanto tempo è il segreto. Se è 1 personaggio, ora deve solo fare 10 test invece di centomila. Se è lungo 2 caratteri, ha solo bisogno di fare 100 test. Senza questa informazione chiave, l'hacker deve fare molti più test prima di trovare il segreto.

un altro problema: spazio di archiviazione recuperabile

C'è anche un altro problema. Se il segreto conosciuto può essere confrontato con il valore di input, è necessario memorizzare il segreto in forma recuperabile. Cerca questo sito per i dettagli relativi alle password, ma questo è spesso considerato una cattiva pratica con l'archiviazione delle password e dovrebbe essere evitato. In generale, con qualsiasi tipo di segreto, se non si deve assolutamente avere il valore grezzo, non dovrebbe essere memorizzato in forma recuperabile. Lo storage irrecuperabile impedisce diversi attacchi, indipendentemente dal fatto che siano importanti per il tuo segreto, dipende da come lo usi.

un'altra cosa: ottimizzazione del compilatore

Il codice, sotto, è pseudo codice. Se dovessi passare il suo equivalente tramite un compilatore o un runtime che esegue l'ottimizzazione, devi essere molto attento a garantire che il codice non venga ottimizzato. Esistono vari trucchi per l'apprendimento di lingue diverse, che non rientrano nell'ambito di questo commento. Da ks a @Polynomial per ricordare questo

    
risposta data 05.01.2015 - 03:37
fonte

Leggi altre domande sui tag