Il metodo Data Encryption / Storage è sicuro?

8

Vorrei innanzitutto dire che so che è una pessima idea memorizzare informazioni sensibili in un database mysql, quindi per favore non rispondere dicendo "DO DO DO IT" o qualcosa del genere effetto. Sto costruendo un sito web per il quale è assolutamente essenziale per memorizzare i numeri di previdenza sociale, e devo essere in grado di recuperare tali dati dal DB (nessun hashing).

Detto questo, ho cercato il modo migliore per crittografare / decrittografare i dati e creare una funzione personalizzata per gestire la crittografia. Ecco la mia funzione di crittografia:

function my_data_encrypt($value){
    $salt=substr(uniqid('', true), 0, 20);
    $key=$salt.MY_PRIVATE_KEY;
    $enc_value=base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5($key), $value, MCRYPT_MODE_CBC, md5(md5($key))));
    return array("enc_value"=>$enc_value, "salt"=>$salt);
}

Quindi fondamentalmente sto generando una stringa casuale per il mio sale, quindi accodando al sale una chiave privata MY_PRIVATE_KEY che è definita in un file di configurazione separato. Quindi utilizzo mcrypt_encrypt per crittografare i dati, quindi base64_encode per rendere sicura la crittografia da memorizzare nel DB. La stringa crittografata e il sale univoco vengono quindi restituiti e archiviati nel DB insieme.

Pensavo che lanciando una "chiave privata" che è stata memorizzata nel file di configurazione (non nel DB) nel mix avrebbe aggiunto un altro livello di sicurezza alla crittografia, in questo modo anche se qualcuno ha hackerato il database e ottenuto la crittografia valore e il sale, non avrebbero ancora tutto ciò di cui hanno bisogno per decodificare i dati.

Può gli esperti di sicurezza riesaminare la mia funzione e farmi sapere se / come i miei dati potrebbero essere violati e se c'è qualcos'altro che potrei fare per migliorarlo?

    
posta BWDesign 10.05.2013 - 12:27
fonte

2 risposte

17

Si sta utilizzando una chiave a 128 bit (output di MD5, quindi 128 bit) con un codice a blocchi che si aspetta una chiave a 256 bit (Rijndael-256). Se PHP fosse stato implementato correttamente, a quel punto sarebbe esploso in faccia. Tuttavia, la documentazione indica che la chiave è semplicemente riempita di zeri fino alla lunghezza richiesta. Se si utilizza una chiave a 128 bit, è meglio usare un cifrario con una chiave a 128 bit, ad esempio Rijndael-128.

Il "sale" è inutile o mal applicato. I sali sono pensati per trattare con chiavi deboli, che possono essere realisticamente recuperate da una ricerca esaustiva, cioè quando le chiavi sono password . Se la tua chiave è una chiave reale, generata correttamente, grassa e casuale, allora il sale è inutile. D'altra parte, se la tua chiave è una password, allora sei nella realtà di hashing della password , che richiederà uno sforzo maggiore.

D'altro canto, IV dovrebbe essere casuale, invece di essere l'hash della chiave. L'uso appropriato del codice a blocchi potrebbe essere:

  • Avere un'unica chiave a 128 bit, generata con un PRNG crittograficamente strong (ad esempio /dev/urandom su Sistemi Linux).

  • Durante la crittografia di un nuovo messaggio, crea una nuova IV casuale con un PRNG strong (ad esempio openssl_random_pseudo_bytes () , che alimenta internamente /dev/urandom o equivalente).

  • Dimentica qualsiasi "sale". Cifra con la tua chiave principale e la IV generata casualmente. Dovrai quindi memorizzare la IV insieme al messaggio crittografato (per un SSN, ti ritroverai con 32 byte: 16 per il IV e 16 per il blocco crittografato).

Quindi si applicano i seguenti avvertimenti:

  • Questa è la crittografia; garantisce riservatezza , non integrità . Qualcuno che può modificare parti del tuo database può avere problemi con il tuo SSN (se solo cambiandolo tra gli utenti). L'integrità del database è un problema difficile e le soluzioni più note non sono buone; implicano un sovraccarico significativo.

  • La riservatezza viene mantenuta solo fino a quando la chiave non viene rivelata. Ma abbiamo immaginato un utente malintenzionato che ottenesse un accesso di lettura insolitamente privilegiato ai contenuti del server e che il server, in generale, conoscesse la chiave. Se si mantiene la chiave in un file, separata dal database, è possibile ottenere una protezione aggiuntiva contro gli attacchi di base SQL injection, che funzionano solo sul contenuto del database; ma tieni presente che hai corretto solo alcune vulnerabilità.

risposta data 10.05.2013 - 13:26
fonte
8

Mi dispiace dirlo a te - stai prendendo rischi davvero pericolosi con quegli SSN. Definiamo rapidamente qualcosa secondo gli standard PCI-DSS:

Q: What is defined as ‘cardholder data’? A: Cardholder data is any personally identifiable data associated with a cardholder. This could be an account number, expiration date, name, address, social security number, etc. All personally identifiable information associated with the cardholder that is stored, processed, or transmitted is also considered cardholder data.

PCI DSS è lo standard per l'archiviazione sicura delle informazioni (preferibilmente finanziaria). Le regole sono severe e le multe per non rispettare sono massicce ($ 5k - $ 100k al mese). SSN, tuttavia, può essere memorizzato in base ad esso, ma ancora una volta, le linee guida sono severe ( pagina 14 di questo documento ). Quindi, anche prima di discutere dell'attuale implementazione, ti consiglio caldamente di sapere in cosa ti stai dedicando.

Mettiamo giù anche alcune cose:

  1. Se stai ritrasmettendo gli SSN (su una pagina o in altro modo) e il tuo livello di trasporto non è sicuro, è come se tutti i livelli di crittografia che hai inserito nel back-end non avessero importanza. Annusare è semplicissimo in questi giorni.
  2. Se stai progettando la tua "suite di crittografia" perché pensi che funzioni, ti ricordi tutte quelle aziende che hanno subito violazioni? Pensavano che anche la loro roba avrebbe funzionato.

Entriamo nei dettagli. Chi non ha dimestichezza con PHP (altri provider di risposte), la funzione mcrypt_encrypt prende come parametri:

  • Cipher - qui, 256 bit AES
  • PK
  • plaintext
  • Modalità (qui, CBC)
  • IV

Rompiamo un po 'la tua funzione. Il primo punto ovvio di "WTF è questa merda" è il tuo uso di md5 per generare chiavi e IV. Sei consapevole del fatto che MD5 presenta serie vulnerabilità, giusto?

Il secondo WTF ovvio è la scelta del codice. AES 512 è utilizzabile su PHP. Questo raddoppierà anche la tua dimensione della chiave. Non solo, ma il tuo uso del sale è piuttosto divertente - questo è ciò che è un IV!

Il terzo WTF ovvio è l'uso di una costante per la tua chiave privata. Ti rendi conto che questa costante persisterà dall'inizializzazione alla chiusura del tuo script, giusto? Non solo, ma scommetto che è definito in chiaro in uno dei file. Ciò significa che:

  • Se qualcuno riesce a trovare un SINGOLO include / file-read vuln sul tuo sito, ha la tua chiave privata
  • Se qualcuno riesce a trovare un'espressione di codice SINGLE vuln sul tuo sito, ha la tua chiave privata

Considera di archiviare la tua chiave privata in modo sicuro (o ancora meglio, memorizzarne solo un hash e richiedere la convalida dell'utente della chiave per decrittografarlo, forzando l'utente a conoscere la chiave per decrittografare le informazioni sensibili).

TL; DR: leggi su PCI-DSS, smetti di inventare cose e capisci gli strumenti che stai usando. Consiglierei un primer in crittografia per iniziare - eventuali obiezioni a Bruce Schneier? Altrimenti, prendi Crittografia pratica (o se preferisci libri più morbidi, Secrets & Lies, supponendo che ci sia un'edizione più recente del 2001).

    
risposta data 10.05.2013 - 13:25
fonte

Leggi altre domande sui tag