Schema di sicurezza del controllo di Sanità, è sicuro? C'è cruft?

-1

Questo articolo: Vita in un mondo post-database: utilizzando la crittografia per evitare le scritture DB

Mi ha chiesto di scrivere questo url-crypt modulo Node.js per convertire un Segreto in stringhe di base64 sicuri urlsafe.

Pensa a un link di verifica email che non ha bisogno di memorizzare i suoi dati nel database. Oppure, un token JWT le cui attestazioni sono segrete anziché base64.

L'idea è di crittografare e archiviare una quantità ragionevole di dati (< 512 caratteri) in < 2k char di base64 (un URL) in modo che possa essere decrittografato in seguito.

L'ho pubblicato su npm e poi ho pensato. È sicuro? Insecure sarebbe inutile per gli altri: - /

Come funziona:

var urlCrypt = require('url-crypt')('super-secret-key');

var data = { hello: 'world', this: 'is a test', of: 'url-crypt' };
var base64 = urlCrypt.cryptObj(data);
var backAgain = urlCrypt.decryptObj(base64);
expect(backAgain).to.eql(data);

Che cosa fa: urlCrypt.cryptObj(obj) :

  • Converte obj in JSON
  • Gzips the JSON
  • Crea 30 byte di sale
  • Crittografa [sale] [gzip] con aes-256-cbc e un pbkdf2 di chiave
  • Converti in base64

E di nuovo indietro.

Il codice è composto da 2 funzioni su un solo file.

Alcune domande specifiche:

  1. Qui aggiunge un po 'di jitter come protezione contro gli attacchi di dizionario. Questo lo rende più strong?

  2. Qui utilizza pbkdf2 per creare la chiave AES. Il sale è costante. Pbkdf2 in questo modo lo rende più strong? L'aggiunta di un parametro di configurazione salt sembra come se avessi solo una chiave più lunga.

  3. Qui mette alcuni dati casuali di fronte al dati reali. Se conoscessi i dati reali ({email: "[email protected]"}) ho pensato che sarebbe stato più facile indovinare il segreto. Questi dati casuali servono a proteggerli. Questo sale aiuta?

  4. Qui ripete l'aes-256- CBS. È utile? La ripetizione rende il token finale più lungo (il che rende meno dati nell'URL), quindi questo è estraneo?

  5. Qual è il modo migliore per rendere più complicato il calcolo, senza rendere il token più lungo?

  6. C'è un modo per migliorare tutto ciò? O qualsiasi altra cosa che potrebbe essere rimossa.

Grazie! È il mio primo modulo incentrato sulla sicurezza, quindi volevo controllarlo in sicurezza.

    
posta Michael Cole 21.02.2015 - 08:35
fonte

1 risposta

2

Ci sono diversi problemi fondamentali.

Prima di tutto, non inventare i tuoi protocolli di sicurezza, soprattutto quando sei un laico. So che è stato detto centinaia di volte prima, so che siamo tutti stanchi di sentirlo, ma è una regola molto importante. Se effettivamente consideri di utilizzare il tuo codice in produzione (che sembra essere il caso), stai già commettendo un grosso errore.

In secondo luogo, la premessa è difettosa. Nell'articolo, questo approccio è commercializzato come un'alternativa semplice e leggera alla memorizzazione dei dati in un database. Ma non è né facile né leggero. Ottenere la crittografia giusta è estremamente difficile, richiede conoscenze specialistiche e un duro lavoro. D'altra parte, l'impostazione di un database è questione di pochi minuti e può essere eseguita da chiunque abbia una conoscenza di base di SQL. In alcuni casi speciali, potrebbe ottenere un vantaggio prestazionale dall'evitare un database lato server, ma questo deve essere misurato nell'applicazione concreta e soppesato gli svantaggi. Non vedo alcuna indicazione che tu abbia effettivamente fatto questo.

In terzo luogo, ci sono problemi concettuali. Tu parli di segreti e crittografia, ma sembra che ciò che realmente desideri sia l'autenticazione e l'integrità, ovvero, vuoi assicurarti che i dati nell'URL provengano effettivamente da te e non siano stati manipolati. In genere la crittografia non impedisce la manipolazione, fornisce solo riservatezza (non vedo perché ne avresti bisogno nel tuo caso). Se vuoi tutte e tre le proprietà contemporaneamente, le cose diventano ancora più complesse. Ora avete bisogno di modalità di cifratura avanzate come la modalità contatore Galois di AES che può o non può essere supportata nel vostro ambiente. Fornire la propria combinazione di crittografia / MAC è non raccomandato. Anche i grandi progetti software hanno rovinato tutto, quindi come un singolo programmatore senza background cripto, le possibilità di commettere un errore sono enormi.

Inoltre non hai pensato al problema di revocare un token. Cosa succede se si scopre che un token è stato compromesso? Cosa succede se un utente ti chiede di cancellarlo immediatamente? Dal momento che non hai alcun controllo sui token dopo averli emessi, questo non è possibile. Tutto quello che puoi fare è aspettare che il token scada, ma questa è difficilmente un'opzione. Quindi probabilmente hai bisogno di un database lato server di qualche tipo, a quel punto l'intero esercizio diventa piuttosto inutile.

Ultimo ma non meno importante, ci sono un sacco di problemi tecnici nel codice:

  • Usare un sale costante è assolutamente sbagliato (come già detto). Non mi è nemmeno chiaro il motivo per cui vorresti utilizzare una chiave basata su password invece di una chiave puramente casuale.
  • Non esiste un vettore di inizializzazione casuale, che è di nuovo un difetto fatale. NodeJS prova a ricavare una IV dal materiale chiave, ma poiché il tuo sale PBKDF2 è costante, anche l'IV è costante.
  • Stai utilizzando i metodi sbagliati. Se leggi manuale , vedrai che il metodo crypto.createCipher() prevede effettivamente una password , non una chiave. Quindi deriva una chiave e un vettore di inizializzazione da questa password (utilizzando un algoritmo piuttosto debole). Per crittografare i dati con una chiave personalizzata, viene utilizzato crypto.createCipheriv() .
  • No, l'aggiunta di dati inutili o l'introduzione di una serie di ripetizioni non aiuta. Fare cose a caso nella speranza che aumenti la sicurezza in genere non è utile nella crittografia.
risposta data 21.02.2015 - 13:10
fonte

Leggi altre domande sui tag