Προς το περιεχόμενο

Προτεινόμενες αναρτήσεις

Δημοσ.

Καλησπερα και χρονια πολλα

 

Εχω στησει node 4.2.3 και θελω να κρυπτογραφησω (salt + hash) passwords πριν τα αποθηκευσω στη ΒΔ, postgreSQL , σε πεδιο varchar (255) 

 

Θελω να χρησιμοποιησω την Link.png Site: pbkdf2 επειδη ειναι μεσα στο node και δε χρειαζεται καποια εξωτερικη βιβλιοθηκη. 

 

Ο κωδικας για τη κρυπτογραφηση ειναι

	var salt = crypto.randomBytes(50);
	salt = new Buffer(salt).toString('hex');

	crypto.pbkdf2(password, salt , 10000, 100, 'sha512',function(err, derivedKey) {
		password  = (new Buffer(derivedKey).toString('hex'));
	});

Το salt δεν ειναι πουθενα μεσα στο hash. Πρεπει να τα ενωσω manually , σαν finalPassword = salt+password ??

 

Παραδοξως δεν εχω βρει παραδειγμα για validation. Οποτε, συμφωνα με οτι δει μεχρι τωρα πρεπει να ειναι καπως ετσι

 

Δεχομαστε οτι τα αποθηκευμενα ειναι finalPassword = salt+password και οτι τα salt εχουν σταθερο μηκος , πχ 10 χαρακτηρες. Παμε

 

Παρε το password που προσπαθει να κανει login, passToBe

 

Παρε το αποθηκευμενο password, finalPassword. Παρε τους πρωτους 10 χαρακτηρες, originalSalt.

 

Κρυπτογραφησε το passToBe με ιδιο αλγοριθμο, ιδιες επαναληψεις και το ιδιο salt, το originalSalt δηλαδη.

crypto.pbkdf2(passΤοBe, originalSalt , 10000, 100, 'sha512',function(err, derivedKey) {
		passΤοBe  = (new Buffer(derivedKey).toString('hex'));
	});

finalPassToBe = originalSalt + passToBe

 

Συγκρινε finalPassToBe με finalPassword , αν ιδιο let him in, αν οχι, get out.

 

Δεν ξερω αν ολο αυτο ειναι ο σωστος τροπος, ουτε το εχω τρελα με κρυπτογραφησεις. Δε ξερω κατα ποσο το παραπανω ειναι ασφαλες και δυνατο σε επιθεσεις.

 

Αν καποιος καταφερει και μου κλεψει τα κρυπτογραφημενα passwords τι τον εμποδιζει να εχει προσβαση και στον κωδικα? Οποτε mporei να δει οτι απο το συνολικο password το salt ειναι 10 χαρακτηρες. Οποτε θα ξερει τι να κρατησει ως σκετο hash. Χωρις salt οι χρονοι σπασιματος πεφτουν δραματικα. Οποτε αυτο δεν αποτελει τεραστιο κενο απο μονο του. Σωστα?

 

Αν μπορει καποιος να μου πει που κανω λαθος η αν ξερει καποια παραδειγματα η καποιο library που να κανει αυτοματη και ασφαλη τη χρηση της pbkdf2. 

 

Ευχαριστω

Δημοσ. (επεξεργασμένο)

Έχει αρκετό ψωμί να ασχοληθεί κανείς εδώ και είναι πολύ ωραία διατυπωμένη ερώτηση.  :)

 

(Τραβηγμένο λίγο για να ταιριάξει) Golden rule of crypto: don't roll your own. Δεν κάνεις κάποιο πολύ χοντρό λάθος, αλλά πολύ σωστά σου λέει η αραχνοαίσθηση να ψάξεις να βρεις κάτι έτοιμο και καθιερωμένο. Δεν ξέρω να σου προτείνω κάτι σε node αλλά αυτή θα ήταν η 100% σωστή προσέγγιση update: not hard to find. Τα υπόλοιπα από δω και κάτω είναι καθαρά για εκπαιδευτικούς σκοπούς.

 

Τι πρέπει να αποθηκεύσεις

 

Αυτό προκύπτει με λίγη "απλή λογική". Έστω ότι παίρνεις passwords p από το χρήστη, τα περνάς από μια συνάρτηση F(p) και αποθηκεύεις το αποτέλεσμα R. Όταν θέλεις να ελέγξεις τα credentials του χρήστη εν τέλει θα χρειαστεί να συγκρίνεις κάτι με το R, οπότε θα χρειαστεί να χρησιμοποιήσεις πάλι την F, οπότε πρέπει να έχεις στα χέρια σου όλες τις εισόδους της. Παράδειγμα:

  1. Plaintext passwords, F(p) = p. Προφανώς δε χρειάζεσαι άλλα δεδομένα.
  2. Απλό hashing, F(p) = hash(p). Όπως παραπάνω.
  3. Hash + salt, F(p) = salt + hash(salt + p). Θα χρειαστείς κάπου να έχεις αποθηκεύσει το hash.
  4. PBKDF2, F(p) = PBKDF2(p, salt, iterations, length, digest_function). Θα χρειαστείς guess what, τα πάντα εκτός από το p που θα στο δώσει πάλι ο χρήστης.

Δε λέω και τίποτα πρωτότυπο απλά το κάνω έτσι για να φανεί πως δεν είναι rocket science. Θα πρέπει θεωρητικά να έχεις finalPassword = salt + iterations + length + digest_f + hash για να μπορέσεις μετά να ξανακαλέσεις την PBKDF2 με τις ίδιες παραμέτρους.

 

Τώρα, επειδή κάποια από αυτά τα πεδία δεν είναι εμφανώς σταθερού μεγέθους (π.χ. τα iterations μπορεί αύριο να γίνουν εφταψήφια) στην πράξη βάζεις κι ένα κατάλληλο separator ανάμεσα στα πεδία (π.χ. ο χαρακτήρας $ χρησιμοποιείται απο δω κι απο κει για παρόμοιο σκοπό) για να ξέρεις πού χωρίζονται.

 

Επίσης με απλή λογική, εφόσον εσύ τα iterations, length και digest_f τα έχεις hardcoded μπορείς να μην ασχοληθείς καν και να βάλεις όπως έγραψες απλά ο,τι μένει: salt + hash. Αυτό δε θα το πρότεινα γιατί στο μέλλον μπορεί να μη θέλεις να τα έχεις πλέον hardcoded ("μπορεί" = "σίγουρα αλλιώς κάνει κρα ο ερασιτεχνισμός"). Βέβαια technically ακόμα κι αν δεν τα βάλεις τώρα, μπορείς αύριο να γράψεις backward compatible κώδικα που να λέει αν το finalPassword μοιάζει να έχει το format όλα μέσα τότε τα εξάγουμε απο κει, αλλιώς default τιμές 10000, 1000, sha2-512. Αλλά γιατί να μπαίνεις σε τέτοιες διαδικασίες, κάντο σωστά από την αρχή, θέλει την ίδια προσπάθεια με το να το κάνεις ερασιτεχνικά.

 

Τι είναι περίεργο

 

Ζητάς 100 bytes output. Πρώτα απ' όλα, πρέπει να είσαι σίγουρος ότι αυτό το νούμερο δεν είναι προβληματικό με οποιοδήποτε τρόπο because crypto is just so easy to fuck up.

 

Στην προκειμένη, η PBKDF2 είναι guaranteed ότι μπορείς να βάλεις όποιο νούμερο θέλεις και αυτό δε θα επηρρεάσει την ασφάλεια του συστήματος πέραν του προφανούς ότι αν βάλεις πολύ μικρό είσαι εκτεθειμένος σε brute force.

Εσύ βέβαια πας στο άλλο άκρο: τα 800 bits που ζητάς είναι πολύ περισσότερα από τα 224-512 του SHA2 που θεωρείται τελείως secure σήμερα, οπότε total overkill. Μπορείς να κάνεις το 800 ίδιο με το block size του hash function (δηλαδή αντί για 100, 64) και πάλι θα είσαι overkill. Και 32 να έβαζες πάλι more than ΟΚ θα ήταν.

 

Τι θέλει προσοχή

 

Ο τρόπος με τον οποίο συγκρίνεις finalPassToBe με finalPassword στο τέλος. Θεωρητικά αν βάλεις ένα απλό ίσον check είσαι ευάλωτος σε "timing attacks" και πρέπει να κάνεις τη σύγκριση με "constant time comparison" (όροι για googling).

 

Εν συντομία, φαντάσου ότι ένα ίσον check θα ήταν υλοποιημένο κάπως έτσι:

function stringEquals(s1, s2) {
    if (s1.length !== s2.length) return false;
    for (i = 0; i < s1.length; ++i) {
        if (s1[i] !== s2[i]) return false;
    }
    return true;
}

Το πρόβλημα εδώ είναι το return false μέσα στη for. Είναι φανερό πως αν s1 το σωστό hash και s2 αυτό που προέρχεται από την είσοδο του χρήστη και διαφέρουν στο πρώτο byte η συνάρτηση θα επιστρέψει γρηγορότερα απ' οτι αν διαφέρουν στο δεύτερο, αν διαφέρουν στο δεύτερο γρηγορότερα απ' ότι αν διαφέρουν στο τρίτο κλπ. Επομένως ένας attacker που ελέγχει το s2 και μπορεί να μετρήσει με σούπερ μεγάλη ακρίβεια το χρόνο που κάνεις για να του ρίξεις πόρτα μπορεί με βάση τις παρατηρήσεις του να μαντέψει ένα ένα όλα τα bytes του s1 εφόσον θεωρητικά όλο το υπόλοιπο χρονικό κόστος του login attempt εκτός από το πόσες φορές έγινε το loop παραμένει σταθερό.

 

Στην πράξη τώρα, no sweat. Aυτό πρώτον είναι εξαιρετικά δύσκολο να γίνει και δεύτερον και σημαντικότερο, ο έλεγχος του attacker πάνω στο s2 είναι θεωρητικός: αφού το s2 προκύπτει με iterations του hash function πάνω στην είσοδο passToBe, το να βρει κάποιος ένα passToBe το οποίο καταλήγει να δώσει μια συγκεκριμένη τιμή σε συγκεκριμένα bytes του s2 ελαφρώς μπακαλίστικα ισοδυναμεί με preimage attack πάνω στην εσωτερική hash function που είναι προφανές ότι πρέπει να απέχει έτη φωτός από την πραγματικότητα για να θεωρούμε πως η hash function είναι cryptographically secure όπως η sha2.

 

Το αναφέρω πάντως για να δεις πρώτον πόσο εύκολο είναι να γίνει η στραβή και δεύτερον επειδή σε άλλες χρήσεις μιας συνάρτησης όπως η PBKDF2 ο έλεγχος του attacker πάνω στο s2 μπορεί να είναι πολύ πιο άμεσος οπότε πρόβλημα.

 

Περι salting

 

Αν καποιος καταφερει και μου κλεψει τα κρυπτογραφημενα passwords τι τον εμποδιζει να εχει προσβαση και στον κωδικα? Οποτε mporei να δει οτι απο το συνολικο password το salt ειναι 10 χαρακτηρες. Οποτε θα ξερει τι να κρατησει ως σκετο hash. Χωρις salt οι χρονοι σπασιματος πεφτουν δραματικα. Οποτε αυτο δεν αποτελει τεραστιο κενο απο μονο του. Σωστα?

 

 

To salt δεν κάνει καμία διαφορά στο χρόνο σπασίματος. Φαντάσου ότι χωρίς salt ο attacker προσπαθεί ξέροντας την F και το finalPassword να βρει μια είσοδο passToBe για την οποία F(passToBe) = finalPassword. Με salt το οποίο γνωρίζει, προσπαθεί να βρει μια passToBe για την οποία F(salt + passToBe) = finalPassword. Η μόνη διαφορά στο χρόνο εκτέλεσης είναι η ένωση strings (ή άλλη αντίστοιχη λειτουργία) salt + passToBe, το κόστος της οποίας είναι αμελητέο. Οπότε το salt δε σε βοηθάει καθόλου εναντίον του brute force. Αλλά επειδή αυτό το νόμισμα έχει δύο όψεις, αντίστοιχα και η γνώση του salt από τον attacker δεν τον βοηθάει κι εκείνον καθόλου να κάνει brute force.

 

To salt απλά βοηθάει στο να μη μπορεί ο attacker να κάνει amortize το κόστος του brute force πάνω σε όλους τους χρήστες, δηλαδή βασικά να κάνει ένα brute force το οποίο θα επιτίθεται παράλληλα σε όλα τα accounts που θα πάρει από τη βάση σου αντί για να χρειάζεται να επιτεθεί σε κάθε ένα ξεχωριστά. Δες http://stackoverflow.com/questions/420843/how-does-password-salt-help-against-a-rainbow-table-attack.

 

Υπόψη όμως ότι για να είναι αποτελεσματικό για τη χρήση που προορίζεται το salt πρέπει να είναι διαφορετικό για κάθε χρήστη (δε χρειάζεται να είναι cryptographically secure και ούτε καν δε χρειάζεται να είναι random αν και στην πράξη θα είναι τουλάχιστον random because why not). Περισσότερα links που βασικά λένε το ίδιο πράγμα.

 

Τέλος, όπως αναφέρεται και σε μερικά από τα παραπάνω links, σε περιπτώσεις που you can never have too much security ενίοτε χρησιμοποιείται και ένα "κρυφό salt" του οποίου ο ρόλος είναι να αναγκάσει τον attacker να αποκτήσει πρόσβαση όχι μόνο στη βάση σου αλλά και σε κάποιο άλλο σύστημα. Το κρυφό αυτό salt όταν υπάρχει είθισται να ονομάζεται... pepper.

Επεξ/σία από defacer
  • Like 7
Δημοσ.

I'm on #teamdefacer :)

 

Μολις ειδα οτι απαντησες, θα τσεκαρω την απαντηση με ηρεμια απο αυριο γιατι τωρα το μυαλο μου ειναι ζαμπον. 

 

Απλα, για την bcrypt που μου προτεινεις, δε ξερω κατα ποσο ειναι ασφαλης, αφου σαν dependency εχει την Link.png Site: node-gyp , η οποια σαν dependencies εχει Microsoft Visual Studio C++ 2013 (για το λαπτοπ μου τουλαχιστον) και για ολες τις windows versions το Windows 7 64bit SDK. 

 

Δε ξερω κατα ποσο ειναι σοφο, απο αποψη ασφαλειας να εγκαταστησω VSC++ και SDKs σε σερβερ (που τρεχει windows server , δε θυμαμαι εκδοση) . Δε ξερω αν κανουν το συστημα πιο αδυνατο η ανοιγουν πορτες που δεν εχω φανταστει. Any thoughts btw?

 

Γι αυτο και αποφασισα να ασχοληθω με PBKDF2, μιας και ειναι baked-in στο node.js και δεν εχει αλλο dependency.

Δημοσ.

Απλα, για την bcrypt που μου προτεινεις, δε ξερω κατα ποσο ειναι ασφαλης, αφου σαν dependency εχει την Link.png Site: node-gyp , η οποια σαν dependencies εχει Microsoft Visual Studio C++ 2013 (για το λαπτοπ μου τουλαχιστον) και για ολες τις windows versions το Windows 7 64bit SDK. 

 

Δε ξερω κατα ποσο ειναι σοφο, απο αποψη ασφαλειας να εγκαταστησω VSC++ και SDKs σε σερβερ (που τρεχει windows server , δε θυμαμαι εκδοση) . Δε ξερω αν κανουν το συστημα πιο αδυνατο η ανοιγουν πορτες που δεν εχω φανταστει. Any thoughts btw?

 

Δεν είδα πουθενά να έχει αυτό το dependency για production. Το έχει για development βέβαια, αλλά δε σου χρειάζεται really.

Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε

Πρέπει να είστε μέλος για να αφήσετε σχόλιο

Δημιουργία λογαριασμού

Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!

Δημιουργία νέου λογαριασμού

Σύνδεση

Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.

Συνδεθείτε τώρα
  • Δημιουργία νέου...