Hash κωδικών πρόσβασης
Για να διασφαλίσουμε την ασφάλεια των χρηστών μας, δεν αποθηκεύουμε τους κωδικούς πρόσβασής τους σε αναγνώσιμη μορφή, αλλά αποθηκεύουμε μόνο το αποτύπωμα (το λεγόμενο hash). Από το αποτύπωμα δεν είναι δυνατή η ανακατασκευή της αρχικής μορφής του κωδικού πρόσβασης. Είναι σημαντικό να χρησιμοποιήσουμε έναν ασφαλή αλγόριθμο για τη δημιουργία του αποτυπώματος. Σε αυτό μας βοηθά η κλάση Nette\Security\Passwords.
Το framework προσθέτει αυτόματα στον DI container μια υπηρεσία τύπου
Nette\Security\Passwords
με το όνομα security.passwords
, στην οποία μπορείτε
να αποκτήσετε πρόσβαση ζητώντας να σας περαστεί μέσω dependency injection.
use Nette\Security\Passwords;
class Foo
{
public function __construct(
private Passwords $passwords,
) {
}
}
__construct ($algo=PASSWORD_DEFAULT, array $options=[]): string
Επιλέγουμε ποιον ασφαλή αλγόριθμο θα χρησιμοποιήσουμε για τη δημιουργία του hash και διαμορφώνουμε τις παραμέτρους του.
Ως προεπιλογή χρησιμοποιείται το PASSWORD_DEFAULT
, δηλαδή η επιλογή
του αλγορίθμου αφήνεται στην PHP. Ο αλγόριθμος μπορεί να αλλάξει σε
νεότερες εκδόσεις της PHP, εάν εμφανιστούν νεότεροι, ισχυρότεροι
αλγόριθμοι hashing. Επομένως, θα πρέπει να γνωρίζετε ότι το μήκος του
τελικού hash μπορεί να αλλάξει και θα πρέπει να το αποθηκεύσετε με τρόπο
που να μπορεί να χωρέσει αρκετούς χαρακτήρες, 255 είναι το συνιστώμενο
πλάτος.
Παράδειγμα ρύθμισης της ταχύτητας hashing του αλγορίθμου bcrypt αλλάζοντας την παράμετρο cost: (το 2020 η προεπιλογή είναι 10, το hashing του κωδικού πρόσβασης διαρκεί περίπου 80ms, για cost 11 περίπου 160ms, για cost 12 περίπου 320ms, όσο πιο αργό, τόσο καλύτερη προστασία, ενώ η ταχύτητα 10–12 θεωρείται ήδη επαρκής προστασία)
// θα κάνουμε hash τους κωδικούς πρόσβασης με 2^12 (2^cost) επαναλήψεις του αλγορίθμου bcrypt
$passwords = new Passwords(PASSWORD_BCRYPT, ['cost' => 12]);
Μέσω dependency injection:
services:
security.passwords: Nette\Security\Passwords(::PASSWORD_BCRYPT, [cost: 12])
hash (string $password): string
Δημιουργεί το hash του κωδικού πρόσβασης.
$res = $passwords->hash($password); // Κάνει hash τον κωδικό πρόσβασης
Το αποτέλεσμα $res
είναι μια συμβολοσειρά που, εκτός από το ίδιο
το hash, περιέχει επίσης τον αναγνωριστικό του χρησιμοποιούμενου
αλγορίθμου, τις ρυθμίσεις του και το κρυπτογραφικό salt (τυχαία δεδομένα
που διασφαλίζουν ότι για τον ίδιο κωδικό πρόσβασης δημιουργείται
διαφορετικό hash). Είναι επομένως συμβατό προς τα πίσω, όταν για
παράδειγμα αλλάζετε τις παραμέτρους, τα hashes που αποθηκεύτηκαν με τη
χρήση προηγούμενων ρυθμίσεων θα μπορούν να επαληθευτούν. Όλο αυτό το
αποτέλεσμα αποθηκεύεται στη βάση δεδομένων, οπότε δεν χρειάζεται να
αποθηκεύετε το salt ή τις ρυθμίσεις ξεχωριστά.
verify (string $password, string $hash): bool
Διαπιστώνει αν ο δεδομένος κωδικός πρόσβασης αντιστοιχεί στο
δεδομένο αποτύπωμα. Λάβετε το $hash
από τη βάση δεδομένων σύμφωνα
με το δοθέν όνομα χρήστη ή τη διεύθυνση email.
if ($passwords->verify($password, $hash)) {
// σωστός κωδικός πρόσβασης
}
needsRehash (string $hash): bool
Διαπιστώνει αν το hash αντιστοιχεί στις επιλογές που δόθηκαν στον κατασκευαστή.
Είναι χρήσιμο να το χρησιμοποιείτε όταν, για παράδειγμα, αλλάζετε την
ταχύτητα hashing. Η επαλήθευση γίνεται σύμφωνα με τις αποθηκευμένες
ρυθμίσεις και αν η needsRehash()
επιστρέψει true
, τότε είναι
απαραίτητο να δημιουργηθεί ξανά το hash, αυτή τη φορά με τις νέες
παραμέτρους, και να αποθηκευτεί ξανά στη βάση δεδομένων. Με αυτόν τον
τρόπο “αναβαθμίζονται” αυτόματα τα αποθηκευμένα hashes κατά τη σύνδεση
των χρηστών.
if ($passwords->needsRehash($hash)) {
$hash = $passwords->hash($password);
// αποθήκευση του $hash στη βάση δεδομένων
}