slevinkelevra Δημοσ. 18 Απριλίου 2013 Δημοσ. 18 Απριλίου 2013 (επεξεργασμένο) Γεια και παλι. Σε προηγουμενο ποστ μου, ειχατε κανει καποιες παρατηρησεις σχετικα με το hashing passwords (insert σε βαση postgresql). Να πω οτι δεν εχω ξανασχοληθει με hashing ποτε...Αποφασισα ν ανοιξω αλλο θεμα για αποριες μου σε hash. Παμε... Για να δημιουργηθει ενα salt συνηθως χρησιμοποιειται η mt_rand. Στο manual της php λεει "not be used for cryptographic purposes [...] consider using openssl_random_pseudo_bytes() instead" (http://php.net/manual/en/function.mt-rand.php) Παλι στο manual της php (http://www.php.net/manual/en/function.crypt.php#111086) ο τυπακος προτεινει την mcrypt_create_iv() Περνω αυτην εδω την wrapper της crypt (http://www.php.net/manual/en/function.crypt.php#105949) και αντικαθιστω την γραμμη $salt .= substr("./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", mt_rand(0, 63), 1); //αντικαθιστω με $salt .= substr("./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", openssl_random_pseudo_bytes(63, $cstrong), 50); $salt .= substr("./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", mcrypt_create_iv(63, MCRYPT_RAND), 50); $salt .= substr("./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", mt_srand(63), 1); Κανω σχολια ολες εκτος απο μια και ξεκιναω να τρεχω τον κωδικα. Το validation δουλευει, συγκρινει κανονικα δηλαδη και μου εμφανιζει ΟΚ. Ερωτηση αρχαριου : καθε φορα που κανω refresh, οι openssl_random_pseudo_bytes και mcrypt_create_iv βγαζουν καθε λιγο ενα στανταρ hash $2y$08$$$$$$$$$$$$$$$$$$$$$$.UrC6Lo4LNk8iLmoi25KEoVzHHTK7tNC το παραπανω το εχω δει τουλαχιστον 10 φορες. Επισης η mt_srand βγαζει μονιμα το ιδιο hash, οσες φορες και να κανω refersh. ΟΚ, λεω, ας δοκιμασω και με αλλο wrapper. Πηρα αυτο (http://www.the-art-of-web.com/php/blowfish-crypt/) που αναφερει στο βημα 3 και ειναι αρκετα "συνηθισμενο" και πιο απλο και εκανα την ιδια δουλεια αντικαθιστωντας την mt rand με τις παραπανω. Και ειχαν ολες την ιδια συμπεριφορα που περιεγραψα παραπανω. Πολυ γενικη η ερωτηση μου, το ξερω, αλλα τι στο καλο γινεται εδω? Ευχαριστω Επεξ/σία 19 Απριλίου 2013 από slevinkelevra
defacer Δημοσ. 19 Απριλίου 2013 Δημοσ. 19 Απριλίου 2013 Για να δημιουργηθει ενα salt συνηθως χρησιμοποιειται η mt_rand. Στο manual της php λεει "not be used for cryptographic purposes [...] consider using openssl_random_pseudo_bytes() instead" (http://php.net/manual/en/function.mt-rand.php) Η χρήση κάποιου random number generator προκειμένου να προκύψει ένα salt δεν είναι cryptographic purpose. Συγκεκριμένα, ένα salt δε χρειάζεται να είναι τυχαίο (με το μαθηματικό/κρυπτογραφικό ορισμό) αλλά απρόβλεπτο. Παράδειγμα: έχω ένα ζάρι που στις πλευρές του γράφει 1,1,1,2,3,4. Ρίχνοντας αυτό το ζάρι το αποτέλεσμα σίγουρα δεν είναι τυχαίο (50% θα φέρνει άσους) όμως είναι απρόβλεπτο (αν σου ζητήσω να μαντέψεις τι θα φέρω στην επόμενη ζαριά δε μπορείς να το κάνεις). Το ότι δε χρειάζεται να είναι τυχαίο προκύπτει άμεσα αν έχεις υπόψη ακριβώς τι δουλειά κάνει το salt (διάβασε για rainbow tables). Επίσης προκύπτει πολύ εύκολα δεδομένου ότι το salt βρίσκεται αποθηκευμένο χωρίς καμία προστασία (προφανώς αν ήταν ευαίσθητο θα το κρύβαμε): η αξία του δεν είναι στο ότι ο επιτιθέμενος δεν το ξέρει, αλλά στο ότι δε μπορεί να προετοιμαστεί γι' αυτό πριν το δει (θεωρούμε δεδομένο ότι θα το δει κάποια στιγμή, αλλιώς δεν είναι και πολύ επιτιθέμενος). Παλι στο manual της php (http://www.php.net/manual/en/function.crypt.php#111086) ο τυπακος προτεινει την mcrypt_create_iv() Έχε υπόψη πρώτον ότι γενικά δε σημαίνει πως ο,τι γράφει κάποιος στα comments ισχύει (δεν το λέω για τον συγκεκριμένο). Δεύτερον, δε θα πας μακριά αν κάνεις πράγματα χωρίς να καταλαβαίνεις γιατί. Στην προκειμένη σου λέει (και έχει δίκιο) ότι η mt_rand() δίνει το πολύ 32 bit εντροπίας (προκύπτει από το μέγεθος του seed). OK, αυτό γιατί είναι πρόβλημα; Επειδή μια κατατοπιστική εξήγηση θα πάρει πάρα πολλή ώρα, θα πω πολύ συνοπτικά ότι 32 bit entropy = το πολύ να πάρεις 2^32 διαφορετικά salts όσο κι αν χτυπιέσαι, άρα στα 2^16 έχεις 50% πιθανότητα να υπάρχουν 2 hashes όπου χρησιμοποιήθηκε το ίδιο salt (birthday attack). Άρα στους 65Κ χρήστες υπάρχει 50% πιθανότητα να μπορείς να χρησιμοποιήσεις κάποιο rainbow table για να σπάσεις δύο passwords, και στους άπειρους χρήστες (αν υποθέσουμε ότι η κατανομή των salts είναι ομοιόμορφη) θα μπορείς να το χρησιμοποιήσεις για να σπάσεις το ένα τετράκις δισεκατομμυριοστό των passwords. Colour me unimpressed. Υποτίθεται πως rainbow table χρησιμοποιείς για να σπάσεις όλα τα (αδύναμα) passwords. Αν η αποτελεσματικότητά του από π.χ. 99% πέσει σε απειροελάχιστο ποσοστό τότε απλά δεν έχει νόημα η χρήση του, άρα και το όλο επιχείρημα περι μικρής εντροπίας δεν είναι ιδιαίτερα πειστικό. Τέλος πάντων, ας πούμε mcrypt_create_iv. Σκοτώνεις μπεκάτσα με πύραυλο αλλά άμα σου περισσεύουν βρε αδερφέ γιατί όχι. Περνω αυτην εδω την wrapper της crypt (http://www.php.net/manual/en/function.crypt.php#105949) και αντικαθιστω την γραμμη Αυτό που κάνεις απλά δεν έχει κανένα απολύτως νόημα. Η mt_rand() που αντικαθιστάς παράγει τυχαιους αριθμούς στο [0, 63], οι οποίοι σε συνδυασμό με το loop και τη substr παράγουν το salt. Καμία από τις συναρτήσεις που βάζεις στη θέση της δεν παράγει τυχαίους αριθμούς, η mt_srand() μάλιστα δεν παράγει απολύτως τίποτα, τυχαίο ή όχι (διάβασες το manual να δεις τι κάνουν?). Επομένως το να περιμένεις ότι απο κει και πέρα τα πράγματα θα δουλέψουν σωστά είναι παράλογο. Σου προτείνω να καταλάβεις πρώτα πώς δουλεύει ο κώδικας που πείραξες και μετά να τον πειράξεις. 3
slevinkelevra Δημοσ. 19 Απριλίου 2013 Μέλος Δημοσ. 19 Απριλίου 2013 Ο defacer εχει απολυτο δικιο για στις τελευταιες παρατηρησεις του. Ξεκιναω να κανω κατι και αμα κολλησω, ποσταρω, παρολα αυτα συνεχιζω και το ψαχνω και μονος μου. Το λεω για να μη νομιζετε οτι απλα κανω ενα copy/paste απο καπου και μετα περιμενω απο εσας να μου βρειτε τη μια και μοναδικη σωστη απαντηση. Απεριγραπτη η γκαφα μου, αλλα δεν ειμαι καφρος. @defacer Ευχαριστω για το χρονο σου. Διαβασα τα links σου, διαβασα και διαφορα αρθρα και αν καταλαβα καλα μου λες... το "προβλημα" της mt rand δεν ειναι και τοσο προβλημα τελικα, απο τη στιγμη που θελει πολλα μεσα ή/και ώρα για να σπασει καποιος 2 passwords, αν υπαρχουν (50% πιθανοτητα). Ετσι κ αλλιως η "δυναμη" της crypt προερχεται απο τον συνδυασμο rounds και salt το οποιο πρεπει να ειναι απροβλεπτο, οχι τυχαιο. Μαζι με ολα αυτα "To avoid this attack (εννοει birthday attack), the output length of the hash function used for a signature scheme can be chosen large enough so that the birthday attack becomes computationally infeasible" (http://en.wikipedia.org/wiki/Birthday_attack). Αρα ενα hash+salt της "προκοπης" αποτελουν αμυνα στο birthday attack. Ολα αυτα "μειωνουν" το προβλημα της mt rand . Αρα... Αν καταλαβα καλα, η mt rand ειναι "ok" ?(ερωτηση παγιδα...) Ποιο ειναι αυτο το hash+salt της προκοπης? Blowfish, SHA512, SHA256, ποσα rounds? Τι ειναι πιο αποτελεσματικο? Και τωρα η θρασυτατη ερωτηση...Αν, αν τελικα δεν βγαλω ακρη με αυτα, η εναλλακτικη phpass πως σας φαινεται? (http://www.openwall.com/phpass/) και γενικοτερα για ασφαλεια, η phpids, επισης πως σας φαινεται, τι γνωμη εχετε? (https://phpids.org/) Ευχαριστω
defacer Δημοσ. 20 Απριλίου 2013 Δημοσ. 20 Απριλίου 2013 Ετσι κ αλλιως η "δυναμη" της crypt προερχεται απο τον συνδυασμο rounds και salt το οποιο πρεπει να ειναι απροβλεπτο, οχι τυχαιο. Ακριβώς. Απλά όταν λέμε "απρόβλεπτο" υποθέτουμε κάποιο μη σαφώς ορισμένο επίπεδο σοβαρότητας (όχι ας πούμε το παράδειγμα με το ζάρι στην κυριολεξία) και επίσης το salt θα πρέπει να έχει και κάποιο λογικό μήκος πληροφορίας (όχι ας πούμε "ποιά μέρα του μήνα γεννήθηκα" = κάτι λιγότερο από 5 bits). Μαζι με ολα αυτα "To avoid this attack (εννοει birthday attack), the output length of the hash function used for a signature scheme can be chosen large enough so that the birthday attack becomes computationally infeasible" (http://en.wikipedia.org/wiki/Birthday_attack). Αρα ενα hash+salt της "προκοπης" αποτελουν αμυνα στο birthday attack. Ολα αυτα "μειωνουν" το προβλημα της mt rand . Ναι, αλλά προσοχή στο salt της προκοπής. Επειδή το αναφέρεις αμέσως μετά το "can be chosen large enough" υποψιάζομαι πως υπάρχει μια παρανόηση. Η mt_rand() σου δίνει απ' ότι είδα στο source 31 bits "τυχαιότητας" κάθε φορά που την καλείς. Το πρόβλημά της όμως είναι πως ο αλγόριθμος είναι ψευδοτυχαίος (όπως λέμε PRNG), που σημαίνει πως είναι ντετερμινιστικός δηλαδή μπορείς να προβλέψεις την έξοδό του αν ξέρεις την είσοδο. Στην προκειμένη περίπτωση, η είσοδος είναι το seed. Αυτό σημαίνει πως δίνοντας το ίδιο seed παίρνεις την ίδια ακολουθία τυχαίων αριθμών κάθε φορά, ανεξάρτητα από το μήκος της. Επομένως αν το σκεφτείς το να φτιάχνεις μεγαλύτερες σε μήκος ακολουθίες (δηλαδή πιο μεγάλα salts μιας και για τέτοια χρήση τις προορίζουμε) δεν έχει κανένα νόημα μιας και σε ένα PRNG ο αριθμός των διαφορετικών salts που μπορεί ποτέ να παραχθούν είναι ίσος με τον αριθμό των διαφορετικών seeds που μπορούν να χρησιμοποιηθούν. Αφού λοιπόν το seed δίνεται μέσω της mt_srand και αφού το όρισμα αυτής είναι int, τυπικά τα πιθανά seeds είναι μόνο 2^32 άρα και ο αριθμός των πιθανών salts είναι στην καλύτερη (και ισχύουσα) περίπτωση επίσης 2^32 αν θεωρήσουμε πως το μήκος του salt είναι σταθερό. Απλά μαθηματικά στα οποία δε χωράει αντίρρηση. Αυτό ακριβώς εννοούσε ο commenter όταν έλεγε "το πολύ 32 bits εντροπίας". Με τη mt_rand() ποτέ δε θα μπορέσεις να έχεις στην ουσία salt μεγαλύτερο από 32 bits, αφού οποιοδήποτε salt όσο μεγάλο κι αν είναι μπορούμε να το ανάγουμε στην 32-bit τιμή του seed που το "παρήγαγε" (το γεγονός πως δεν την ξέρουμε και ούτε μπορούμε να τη μάθουμε δεν παίζει ρόλο, αρκεί που ξέρουμε ότι γίνεται). Αν καταλαβα καλα, η mt rand ειναι "ok" ?(ερωτηση παγιδα...) Ναι, μια χαρά είναι. Για την ακρίβεια, μπορείς να πάρεις και μεγαλύτερα από 32 bit salts μ' αυτή: απλά την κάνεις seed περισσότερες από μία φορές με άσχετες μαθηματικά μεταξύ τους τιμές seeds. Ο συνολικός αριθμός bits εντροπίας που θα βάλεις στην είσοδο (προκύπτει από το είδος και τον αριθμό των seeds) θα είναι ίδιος με το πραγματικά τυχαίο πληροφοριακό περιεχόμενο του salt που θα πάρεις σαν έξοδο. Επίσης, το salt που χρησιμοποιεί η bcrypt είναι ακριβώς 128 bits. Επομένως, το να παράγεις salt για bcrypt χρησιμοποιώντας περισσότερα από 128 bits εντροπίας δεν προσφέρει τίποτα. Ποιο ειναι αυτο το hash+salt της προκοπης? Blowfish, SHA512, SHA256, ποσα rounds? Τι ειναι πιο αποτελεσματικο? O Blowfish είναι αλγόριθμος συμμετρικής κρυπτογράφησης, οι SHA είναι cryptographic hash functions. Τελείως ανόμοια πράγματα. H bcrypt είναι στα χαρτιά μια key derivation function που χρησιμοποιεί το blowfish για να επιτύχει (με κάπως πολύπλοκο τρόπο) ένα αποτέλεσμα μαθηματικά ισοδύναμο με το "κάνω hash και συγκρίνω τα hashes". Επομένως technically το σωστό είναι να πεις "bcrypt vs sha" και όχι "blowfish vs sha". Σημείωση: Για να μη μπερδευόμαστε, υπόψιν ότι στην παρούσα κουβέντα χρησιμοποιώ τη λέξη bcrypt για να αναφερθώ σε 2 διαφορετικά (αν και σχετικά) πράγματα: Αυτό που κάνει η bcrypt η KDF είναι ένα μέρος μόνο από αυτό που κάνει η bcrypt() η function της PHP. Η τελευταία έχει βέβαια την πρώτη σα βάση αλλά επιπλέον κάνει και διαδικαστικά πράγματα τα οποία είναι φυσικά απαραίτητα για πρακτική εφαρμογή αλλά δεν αποτελούν μέρος της bcrypt KDF στα χαρτιά. Απάντηση στην ερώτηση: το απολύτως σημαντικό είναι να στηθεί σωστά ο μηχανισμός, κάτι που είναι πολύ δύσκολο όπως λένε γιατί στην κρυπτογραφία ή ξέρεις 101% τι κάνεις ή αλλιώς την έκατσες. Αν το χεις να στήσεις σωστά το μηχανισμό με άνεση τότε η επιλογή μεγέθους salt και rounds κλπ είναι αστεία λεπτομέρεια που σίγουρα μπορείς να κάνεις σωστά. Στην πράξη: με 128 bit salt και bcrypt και 8Κ rounds (δηλαδή work factor 13 στην bcrypt της PHP) είσαι υπερ-εξασφαλισμένος στο ότι όποιος θέλει να σου πάρει τα δεδομένα θα προτιμήσει τη δωροδοκία ή τον εκβιασμό από το brute force. Και τωρα η θρασυτατη ερωτηση...Αν, αν τελικα δεν βγαλω ακρη με αυτα, η εναλλακτικη phpass πως σας φαινεται? (http://www.openwall.com/phpass/) και γενικοτερα για ασφαλεια, η phpids, επισης πως σας φαινεται, τι γνωμη εχετε? (https://phpids.org/) Βγάλε άκρη με αυτά. To RFC της PHP για το password hashing API έχει link για έτοιμη υλοποίηση σε PHP κώδικα την οποία μπορείς να πάρεις και να χρησιμοποιείς από τώρα (και όταν πας σε 5.5 να το γυρίσεις στις ενσωματωμένες χωρίς να χρειαστεί να κάνεις καμία αλλαγή στον κώδικά σου). To phpass είναι μια χαρά αν και πλέον δεν έχει ιδιαίτερο λόγο ύπαρξης, οπότε απλά προσπέρασέ το. Το phpids είναι κάτι τελείως διαφορετικό και δε μου γεμίζει το μάτι ούτε στο ελάχιστο. Είναι προφανές πως λειτουργεί με τη λογική του blacklist και "όπως όλοι ξέρουμε" στον τομέα της ασφάλειας το blacklisting είναι το αμέσως καλύτερο στάδιο από το "μπάτε σκύλοι αλέστε": This is a dangerous strategy, because the set of possible bad data is potentially infinite. Adopting this strategy means that you will have to maintain the list of "known bad" characters and patterns forever, and you will by definition have incomplete protection. Άρα όχι. 1
defacer Δημοσ. 28 Απριλίου 2013 Δημοσ. 28 Απριλίου 2013 Πριν λίγο έτυχε να πετύχω από Twitter αυτό, το οποίο είναι πολύ σχετικό με την παραπάνω συζήτηση και το προτείνω για ανάγνωση σε οποιονδήποτε τη βρήκε χρήσιμη ή/και ενδιαφέρουσα. 1
Προτεινόμενες αναρτήσεις
Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε
Πρέπει να είστε μέλος για να αφήσετε σχόλιο
Δημιουργία λογαριασμού
Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!
Δημιουργία νέου λογαριασμούΣύνδεση
Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.
Συνδεθείτε τώρα