Due prende la crittografia PHP bidirezionale - quale è preferibile?

7

Ho bisogno di crittografare alcuni dati e averli decrittografati in un secondo momento. I dati sono legati a utenti specifici. Ho raccolto due possibili soluzioni ...

1 : il primo è derivato dai documenti ufficiali (esempio # 1 @ link ):

function encrypt($toEncrypt)
{
    global $key;
    $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
    $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
    return base64_encode($iv . mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $toEncrypt, MCRYPT_MODE_CBC, $iv));
}

function decrypt($toDecrypt)
{
    global $key;
    $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
    $toDecrypt = base64_decode($toDecrypt);
    return rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, substr($toDecrypt, $iv_size), MCRYPT_MODE_CBC, substr($toDecrypt, 0, $iv_size)));
}

La chiave viene generata una volta utilizzando:

pack('H*', bin2hex(openssl_random_pseudo_bytes(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC))));

1.1 : ho notato che il risultato cifrato termina sempre con due segni di uguale ('=='). Perché? - L'uso di bin2hex () e hex2bin () in encrypt () e decrypt () invece di base64_encode () / base64_decode () non produce questi risultati.

1.2 : L'utilizzo di bin2hex () / hex2bin () avrà conseguenze sull'esito (diverso dalla lunghezza)?

1.3 : sembra esserci qualche discussione sull'opportunità o meno di chiamare una funzione trim sul risultato di ritorno durante la decrittografia (questo vale anche per la soluzione di seguito). Perché sarebbe necessario?

2 : la seconda soluzione viene da qui, Stackoverflow ( link ):

function encrypt($key, $toEncrypt)
{
    return base64_encode(mcrypt_encrypt(MCRYPT_RIJNDAEL_256, md5($key), $toEncrypt, MCRYPT_MODE_CBC, md5(md5($key))));
}

function decrypt($key, $toDecrypt)
{
    return rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, md5($key), base64_decode($toDecrypt), MCRYPT_MODE_CBC, md5(md5($key))), "
function encrypt($toEncrypt)
{
    global $key;
    $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
    $iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
    return base64_encode($iv . mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $toEncrypt, MCRYPT_MODE_CBC, $iv));
}

function decrypt($toDecrypt)
{
    global $key;
    $iv_size = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
    $toDecrypt = base64_decode($toDecrypt);
    return rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, substr($toDecrypt, $iv_size), MCRYPT_MODE_CBC, substr($toDecrypt, 0, $iv_size)));
}
"); }

Sono consapevole che entrambi gli approcci alla gestione delle chiavi sono intercambiabili, li ho volutamente resi diversi sotto questo aspetto, al fine di evidenziare le possibili soluzioni, per favore sentitevi liberi di mescolare e abbinare.

Personalmente ritengo che il primo offra una sicurezza più stretta dal momento che sia il vettore chiave che quello di inizializzazione sono correttamente randomizzati. La seconda soluzione, tuttavia, offre qualche forma di non prevedibilità poiché la chiave è unica per ogni pezzo di dati crittografati (anche se soffre della debole randomizzazione di md5 ()). Ad esempio, la chiave potrebbe essere il nome dell'utente.

3 : quindi, quale è preferibile? Sono leggermente al buio poiché la risposta StackOverflow ha ottenuto ben 105 voti. Altri pensieri, suggerimenti?

4 : domanda bonus !: Non sono incredibilmente intelligente sugli aspetti di sicurezza del server, ma ovviamente ottenere l'accesso ai file PHP potrebbe esporre la chiave, che come risultato diretto, renderebbe la crittografia inutile, presumendo che l'attaccante abbia anche accesso al DB. C'è un modo per oscurare la chiave?

Grazie per aver letto e buona giornata!

    
posta user2026991 09.10.2014 - 10:37
fonte

2 risposte

1

Le due crittografie sono equivalenti. Puoi aggiungere un wrapper per utilizzare un approccio come sostituzione drop-in dell'altro:

/**
* Uses the one-parameter method as if it was the 2-parameter one.
*/
function buhlencrypt($keya, $data) {
   global $key;
   $key = $keya;
   return encrypt($data);
}

/**
* Uses the two-parameter method as if it was the one-parameter.
*/
function weidencrypt($data) {
   global $key;
   return encrypt($key, $data);
}

La "prevedibilità" di MD5 aggiunge un livello trascurabile se "insicurezza": il 99,9999% degli utenti subirà l'hacking dei dati perché ha scelto una password insignificante o l'ha annotata nella sua rubrica o l'ha lasciata su una nota gialla sotto la tastiera. Un attacco professionale inciderà il server e raccoglierà tutte le password piuttosto che bruteforcing di un MD5 (vedi sotto, in risposta alla domanda 4).

1.1: I've noticed that the encrypted result always ends in two equal signs ('=='). Why? - Using bin2hex() and hex2bin() in encrypt() and decrypt() instead of base64_encode()/base64_decode() respectively does not yield these results.

La codifica Base64 funziona sostituendo gruppi di tre byte binari (3 x 8 = 24 bit) con quattro caratteri ASCII-6 (4 x 6 = 24 bit). Ciò significa che il testo di input deve avere una lunghezza multipla di tre e l'output avrà sempre un multiplo di lunghezza di quattro.

Per garantire ciò, Base64 aggiunge uno speciale padding al suo output per indicare se ci sono uno o due caratteri "ignorabili". E poiché Rijndael produce un output multiplo di 16, l'ultimo 16-blocchi viene sempre riempito alla lunghezza 18.

1.2: Will using bin2hex()/hex2bin() have any consequence on the outcome (other than length)?

Assolutamente no.

1.3: There seems to be some discussion whether or not to call a trim-function on the return result when decrypting

Questo perché Rijndael usa anche un blocco di dimensioni fisse, quindi se si dovesse cifrare 17 byte, sarebbe diviso in due blocchi da 16 byte, dando 32 byte di cui gli ultimi 15 sono padding. Poiché Rijndael non prevede di indicare la rimozione del pad (ad esempio non memorizza la lunghezza del testo in chiaro), l'output avrà un'imbottitura azzerata che potrebbe richiedere la rimozione. In alcuni contesti questo potrebbe non essere necessario poiché un padding zero potrebbe essere ignorato, non importa quale.

4: Bonus question!: I'm not incredibly brainy on server security aspects, but obviously gaining access to the PHP files would expose the key, which as a direct result, would render the encryption useless, assuming the attacker also has access to the DB. Is there any way to obscure the key?

Se lo fai simmetricamente, l'accesso ai file PHP consentirà anche di rimuovere l'oscuramento. Verifica quale livello di accesso potresti avere una volta in possesso dei file PHP. Se il suo accesso è vicino al completamento, non ha molto senso offuscare la chiave.

Tuttavia, puoi farlo, anche se in modo indiretto.

Aggiungi al tuo utente tre proprietà del modello (cioè due tabelle di colonne) chiamate UserKey, RootKey e RootKeyOK. Ogni utente riceve una tripletta.

Quando un utente si registra, si genera un IV casuale e lo si crittografa utilizzando la password dell'utente, memorizzandola in UserKey. Lo memorizzi anche in chiaro in RootKey e imposta RootKeyOK su FALSE.

Quando l'utente cambia la password, si utilizza la vecchia password per decrittografare la UserKey e ricodificarla con la nuova password. Non è necessario toccare i RootKeys.

Ogni volta che l'amministratore accede, sfoglia il database dell'utente per le chiavi non OK; per ognuno di essi crittografa il RootKey con la password dell'amministratore e imposta RootKeyOK su TRUE. Questo può essere fatto automaticamente.

Ora nel tuo database hai:

  • HashedPassword --- inutilizzabile da un utente malintenzionato poiché si tratta di un hash.
  • UserKey --- inutilizzabile poiché è crittografato
  • RootKey --- utilizzabile, SE è ancora chiaro, ma solo per i dati di questo utente

Quando l'utente ha effettuato il login ed è necessario crittografare qualcosa che solo lui (e l'amministratore) possono leggere, usa la sua password (ha effettuato l'accesso, quindi è in memoria) per decodificare la userKey e usa la userkey per crittografare il i dati.

Ovviamente, se hai bisogno di crittografare qualcosa quando né l'utente né l'amministratore sono loggati, questo approccio non funzionerà - dovrai memorizzarlo non crittografato con un flag che dice che deve essere crittografato, e farlo non appena l'utente o l'amministratore effettuano il login. Mentre puoi farlo in modo trasparente a entrambi, in verità i dati potrebbero rimanere in chiaro per lunghi periodi sul server, vulnerabile all'acquisizione del database (dall'irruzione remota al furto del disco rigido).

    
risposta data 09.10.2014 - 15:31
fonte
0

Mi è piaciuto questo openssl_encrypt , ce ne sono diversi, puoi provare:

link

    
risposta data 18.01.2018 - 18:46
fonte

Leggi altre domande sui tag