Sta usando PDO e le istruzioni preparate correttamente per un accesso sicuro?

Ancora una volta cercano aiuto con la sicurezza PHP e un sistema di login. Mi chiedo se l'ho fatto correttamente qui. Se non fossi abbastanza specifico ovunque ti preghiamo di chiedere, qualsiasi aiuto è molto apprezzato. Sto cercando di creare un sistema di accesso sicuro, solo per scopi di apprendimento. ecco il codice:

require("constants.php"); $DBH = new mysqli($dbhost, $dbuser, $dbpass, $dbname); function createSalt() { $length = mt_rand(64, 128); $salt = ''; for ($i = 0; $i < $length; $i++) { $salt .= chr(mt_rand(33, 255)); } return $salt; } //Salt function created by ircmaxell function registerNewUser() { //Check to see if Username Is In Use// $q = $DBH->prepare("SELECT id FROM users WHERE username = ?"); $username = filter_var($username, FILTER_SANITIZE_STRING); $data = arrays($username); $q->execute($data); $row = $q->fetch(); if ($row === false) { //If Username Is Not Already In Use Insert Data// $hash = hash('sha256', $pass); $salt = createSalt(); $hash = hash('sha256', $salt . $hash . $pass); //UPDATED $data = arrays($username, $hash, $salt); $qInsert = $DBH->prepare( "INSERT INTO users (username, password, salt) values (?, ?, ?)" ); $qInsert->execute($data); //Inserts User Data Into Table// } } 

Sembra buono finora. Ho tre suggerimenti, però:

  1. Scegli un sale più lungo
  2. Non conservare salt e password digest separatamente
  3. Se la connessione del database non è su localhost utilizzare un connettore di database diverso: PDO non support (ancora) connessioni SSL

EDIT: Inoltre, validationre l'input che un client fornisce come "username". Ma dal momento che il tuo esempio di codice è solo un estratto, credo che lo stai facendo.

EDIT # 2: Quando ho detto, "non memorizzare il sale e la password separatamente" intendevo incorporare il sale nell'hash della password memorizzata. Dato che l'algorithm hash di tua scelta produce una string abbastanza lunga (64 caratteri) composta da [0-9a-f] potresti voler contemplare la generazione di un salt di lunghezza random (crediti a ircmaxell qui) e concatenarlo all'inizio o fine dell'hash della password. Quindi finirai per memorizzare valori di lunghezza variabile (da 96 a 128 caratteri) senza significato (per gli estranei):

 $hash = hash('sha256', $pass); $salt = substr(hash('sha256', mt_rand(0, 1337)), mt_rand(0, 31), 32); $hash = $salt . hash('sha256', $salt . $hash . $pass); 

Un suggerimento Aggiungi la password nel process di hash salting:

 $hash = hash('sha256', $pass); $salt = createSalt(); $hash = hash('sha256', $salt . $hash . $pass); 

Il motivo è evitare le collisioni (anche se con SHA-256 è piuttosto improbabile). Diciamo che c'è una string che si scontra con la bar password quando si esegue sha256 … L' $hash dal primo round sarebbe identico, quindi anche il secondo round di hash produrrà risultati identici:

 $hash = hash('sha256', 'foo'); // "test" for example $hash = hash('sha256', 'bar'); // "test" since it's a collision $newHash = hash('sha256', $salt . $hash); //The same for both foo and bar! 

Considerando che se si reintroduce la password nel secondo round, non si scontrerà direttamente poiché la string è diversa per each hash round …

Modifica: per quanto riguarda la salatura, consiglierei qualcosa come questo (multipiattaforma):

 function createSalt() { $length = mt_rand(64, 128); $salt = ''; for ($i = 0; $i < $length; $i++) { $salt .= chr(mt_rand(33, 255)); } return $salt; } 

Usa caratteri al di fuori dell'intervallo normale (molto più alto), ma esclude i caratteri comuni di controllo e spazi bianchi che potrebbero essere rimossi dal database (o ritagliati). Si noti che restituisce una string ISO-8859-1 (Latin-1) valida. Non è una string UTF-8 valida. Quindi assicurati che il set di caratteri della colonna sia buono, o nel caso peggiore cambi da 255 a 127 nel codice sopra (ma questo riduce notevolmente la forza del sale) …