Hasha lösenord med bcrypt

PHPportalen Forum Index » Tips och Trix
Lägg ett bokmärke på hela tråden
Skapa nytt inlägg   Svara på inlägget
Visa föregående ämne :: Visa nästa ämne  
Startad av: Meddelande
marabou
Administratör



Medlem i: 5279 dagar
Från: Sveriges framsida
Status: Offline



#711581
Inlägg Skrivet: 2011-08-11 11:17      Ämne: Hasha lösenord med bcrypt Citera

Det pågår många diskussioner om hur man ska lagra lösenord. Hashmetoder som md5, sha1, sha512 osv. är relativt lätta att knäcka även om man använder salt.
Säkerhetsexperter rekommenderar istället bcrypt som är baserat på Blowfish-krypteringen, men bcrypt är ingen kryptering utan en hashmetod ("envägskryptering").

Fördelen med bcrypt är att den kräver salt och att det är ruskigt långsam (vilket i praktiken gör den omöjlig att knäcka). En av bcrypts fördelar är att den kan göras långsammare i takt med att hårdvara blir snabbare.

Läs mer om bcrypt här:
http://codahale.com/how-to-safely-store-a-password/

Så hur använder man bcrypt i PHP?

PHP:
1:
<?php
2:
 
3:
function bcrypt($password$salt$rounds=12) {
4:
 
5:
    // Kolla om bcrypt är tillgängligt på servern
6:
    if (CRYPT_BLOWFISH != 1) {
7:
        throw new Exception("bcrypt stöds inte. Se http://php.net/crypt");
8:
        return;
9:
    }
10:
 
11:
    // Kolla så rounds är inom tillåtet intervall
12:
    if ($rounds 4)
13:
        $rounds 4;
14:
    else if ($rounds 31
15:
        $rounds 31;
16:
 
17:
    // Skapa ett prefix för att tala om för crypt att vi vill använda Bcrypt
18:
    $salt_prefix sprintf('$2a$%02d$'$rounds);
19:
    
20:
    // Kolla om saltet innehåller ogiltiga tecken:
21:
    if (!preg_match('#^[A-Za-z0-9./]{22}$#'$salt)) {
22:
        // Saltet är inte bcrypt-säkert. Gör om till 22 tecken (A-Za-z0-9./)
23:
        $new_salt base64_encode($salt);
24:
        if (strlen($new_salt) < 22)
25:
            $new_salt .= base64_encode(md5($salt));
26:
        $salt substr($new_salt022);
27:
        $salt str_replace(array('+''-'), '.'$salt);
28:
        $salt str_replace(array('=''_'), '/'$salt);
29:
    }
30:
 
31:
    // hasha lösenordet med bcrypt
32:
    return crypt($password$salt_prefix.$salt);
33:
 
34:
}

Sedan för att kolla om lösenordet är korrekt, exempel:
PHP:
1:
<?php
2:
 
3:
$statiskt_salt 'En sträng som kan användas som salt...';
4:
 
5:
$anvandarnamn $_POST['username'];
6:
$losenord $_POST['password'];
7:
 
8:
$salt $statiskt_salt $anvandarnamn;
9:
$hash bcrypt($losenord$salt);
10:
 
11:
if ($hash == $losenordet_fran_databasen)
12:
  echo "Rätt lösenord";
13:
else
14:
  echo "Fel lösenord";

Som ni förstår är ovanstående endast ett exempel och måste självklart anpassas till er egen kod, men bcrypt-funktionen kan användas som den är.

Notera att saltet för bcrypt måste vara 22 tecken A-Z a-z 0-9 samt . och /.
Dock har jag skrivit så min bcrypt-funktion gör om vilket salt som helst till att vara 22 tillåtna tecken. Alltså kan ni använda det salt ni använder idag Rolling Eyes
 

_________________
"Never argue with stupid people. They will bring you down to their level and beat you with experience."
- Mark Twain
Till toppen på sidan
Visa användarprofil Skicka privat meddelande Besök användarens hemsida
Sawny



Medlem i: 3135 dagar

Status: Offline



#711617
Inlägg Skrivet: 2011-08-11 18:07      Ämne: Citera

Citat:
Hashmetoder som md5, sha1, sha512 osv. är relativt lätta att knäcka även om man använder salt.


EDIT2:
Räknade fel, har ändrat så det blev rätt nu. Tack emilV.
Ändrade även salt längden från 10 till 15. Om längden är 10 så går det på max 42 dagar om man gör 500 miljarder md5's per sekund.

Nej, inte om man använder salt.

Ett salt som är på 15 tecken, a-zA-Z0-9 + ?!$@% tar 16 million, 2 thousand and 517 år att knäcka.

67 möjliga tecken ^ 15 tecken långt salt = 2461059085914092013369600043 kombinationer.

Även om du knäcker 5 triljoner (5000000000000) md5s per sekund så skulle det ta ca 16002517 år att vara helt säker på att ha knäckt bara saltet.


http://www.wolframalpha.com/input/?i=round%2867+^+15+%2F+5000000000000+%2F+60+%2F+60+%2F+24+%2F+356%29


EDIT1:
Dock gäller det ju att hackaren inte har tillgång till saltet.
Långsammare krypteringar skyddar ju då användarna som valt svaga lösenord.

Senast ändrad av Sawny den 2011-08-12 14:09, ändrad totalt 1 gång
 

_________________
HTML, CSS, PHP, JS
Till toppen på sidan
Visa användarprofil Skicka privat meddelande
hallis



Medlem i: 5819 dagar
Från: Stockholm
Status: Offline



#711633
Inlägg Skrivet: 2011-08-12 09:20      Ämne: Citera

Sawny skrev:
EDIT:
Dock gäller det ju att hackaren inte har tillgång till saltet.
Långsammare krypteringar skyddar ju då användarna som valt svaga lösenord.


Om hackaren inte har tillgång till saltet skall det absolut inte spela någon roll om användaren har ett svagt lösenord eller ej, du saltar ju med en unik sträng som gör att lösenordet inte skall gå att gissa.

När man talar om hur säkert en lösenordshantering är räknar man alltid med att hackaren har tillgång till allt. Sen ställer man inte frågan OM lösenordet går att hacka utan hur långtid det tar, därför är en långsam funktion att föredra.

Jag ska dock tillägga att jag inte lever som jag lär, jag använder sha1 med dynamiskt och statisk salt. Dock sätter jag höga krav på att användarens lösenord skall vara >6 tecken långt innehålla versaler och gemener samt siffror.
 

_________________
Utvecklingsbloggen
Till toppen på sidan
Visa användarprofil Skicka privat meddelande Besök användarens hemsida
Jalet



Medlem i: 5292 dagar
Från: Järfälla, Kallhäll
Status: Offline



#711634
Inlägg Skrivet: 2011-08-12 09:45      Ämne: Citera

hallis skrev:
...Dock sätter jag höga krav på att användarens lösenord skall vara >6 tecken långt innehålla versaler och gemener samt siffror.


Detdär med att tvinga användre att använda vissa tecken vet jag inte om jag tror på riktigt. Användare som tvingas använda vissa tecken tenderar att skriva upp sina lösenord i dokument eller på papper. Därav så finns lösenordet i klartext och för hackaren är det då inte speciellt svårt att ta sig in i systemet förklädd till en användare.

Säkerheten bör därför istället ligga på servernivå, gör allt du kan för att hålla hackern borta från servern & se till att kryptera lösenordet med både statiska & dynamiska salt. Detta har dock gång på gång visats vara svårt då hackare gång på gång tagit sig in i långt mer avancerade system (NASA, FBI CIA) än de som vanligvis diskuteras på detta forum.

Sen kan även en idé vara att lösenorden byts ut med jämna mellanrum.

Hur pass säkert systemet måste vara ska sjävlklart ställas i förhållande till applikationens syfte & graden av känslig information som finns där.
 
Till toppen på sidan
Visa användarprofil Skicka privat meddelande Skicka e-post Besök användarens hemsida
EmilV
Ex-Moderator



Medlem i: 5924 dagar
Från: Lilla Edet
Status: Offline



#711636
Inlägg Skrivet: 2011-08-12 09:54      Ämne: Citera

Bra funktion, marabou. Dock undrar jag om det är så smart att göra en massa magiskt med saltet inuti funktionen. Är det inte bättre att ha förvillkor till funktionen och tvinga programmeraren att göra rätt?
 

_________________
Tänk!

EmilVikström.se | Bloglovin.com
Till toppen på sidan
Visa användarprofil Skicka privat meddelande Besök användarens hemsida
Sawny



Medlem i: 3135 dagar

Status: Offline



#711638
Inlägg Skrivet: 2011-08-12 10:29      Ämne: Citera

hallis skrev:
Sawny skrev:
EDIT:
Dock gäller det ju att hackaren inte har tillgång till saltet.
Långsammare krypteringar skyddar ju då användarna som valt svaga lösenord.


Om hackaren inte har tillgång till saltet skall det absolut inte spela någon roll om användaren har ett svagt lösenord eller ej, du saltar ju med en unik sträng som gör att lösenordet inte skall gå att gissa.

Jag ska dock tillägga att jag inte lever som jag lär, jag använder sha1 med dynamiskt och statisk salt. Dock sätter jag höga krav på att användarens lösenord skall vara >6 tecken långt innehålla versaler och gemener samt siffror.


Den unika strängen måste antingen genereras på samma sätt varje gång man loggar in, eller så måste den vara sparad någon stans. Om hackaren har tillgång till allt så spelar den unika strängen inte så stor roll.

Man kan ju kräva att användaren ska ha 6 tecken storasmå + siffror.
 

_________________
HTML, CSS, PHP, JS
Till toppen på sidan
Visa användarprofil Skicka privat meddelande
intedinmamma



Medlem i: 3508 dagar
Från: Göteborg
Status: Offline



#711639
Inlägg Skrivet: 2011-08-12 10:32      Ämne: Citera

Tänkvärt. Smile
 

_________________
Statistiskt sett? Kanske.
Till toppen på sidan
Visa användarprofil Skicka privat meddelande
marabou
Administratör



Medlem i: 5279 dagar
Från: Sveriges framsida
Status: Offline



#711646
Inlägg Skrivet: 2011-08-12 13:06      Ämne: Citera

EmilV skrev:
Bra funktion, marabou. Dock undrar jag om det är så smart att göra en massa magiskt med saltet inuti funktionen. Är det inte bättre att ha förvillkor till funktionen och tvinga programmeraren att göra rätt?

Kan hålla med om att det vore bättre att programmeraren gör rätt från början men det blir mer kod varje gång man skall hasta ett lösenord och saltet med rätt tecken måste lagras någonstans. När jag skrev denna funktionen tänkte jag på hur jag själv gör och jag brukar använda användarnamn eller användar-id som dynamiskt salt, för då behöver jag inte lagra ytterligare ett salt någonstans. Därför känns det smidigt att bara kunna skicka med användarnanmnet och ett statiskt salt så rättar funktionen själv till det.
Om programmeraren själv skickar in ett korrekt salt så används det.
 

_________________
"Never argue with stupid people. They will bring you down to their level and beat you with experience."
- Mark Twain
Till toppen på sidan
Visa användarprofil Skicka privat meddelande Besök användarens hemsida
hallis



Medlem i: 5819 dagar
Från: Stockholm
Status: Offline



#711648
Inlägg Skrivet: 2011-08-12 15:21      Ämne: Citera

intedinmamma skrev:
Tänkvärt. Smile

Läsvärt

Sawny skrev:
Den unika strängen måste antingen genereras på samma sätt varje gång man loggar in, eller så måste den vara sparad någon stans. Om hackaren har tillgång till allt så spelar den unika strängen inte så stor roll.

Just i det exemplet skrev jag "Om hackaren inte har tillgång till saltet" - det tar inte mycket längre tid att lista ut vJk24f#2" än "sommarnatt" om du har ett unikt sal likt KLjhsdaf785/(%98nJHSD+_:324 innan/efter om ingen känner till det.

Och i det stycket du inte valde att citera skrev jag "Sen ställer man inte frågan OM lösenordet går att hacka utan hur långtid det tar", oavsett hur långt/komplicerat lösenord du har kommer det gå att bryta ur, det är bara en tidsfråga. Därför skall man använda en långsam metod - inte för de som t ex har "sommarnatt" som lösenord.
 

_________________
Utvecklingsbloggen
Till toppen på sidan
Visa användarprofil Skicka privat meddelande Besök användarens hemsida
Olof84



Medlem i: 2553 dagar

Status: Offline



#732949
Inlägg Skrivet: 2013-06-15 07:49      Ämne: Citera

Ursäkta att jag hoppar in i denna tråd ett par år senare. Men vad tror ni om denna bcrypt lösning som jag hittade på stackoverflow (se svaret):
http://stackoverflow.com/questions/4795385/how-do-you-use-bcrypt-for-hashing-passwords-in-php

Det verkar som att den funktionen genererar ett eget salt lösenord, vilket kanske är praktiskt?
 
Till toppen på sidan
Visa användarprofil Skicka privat meddelande
marabou
Administratör



Medlem i: 5279 dagar
Från: Sveriges framsida
Status: Offline



#732982
Inlägg Skrivet: 2013-06-15 18:46      Ämne: Citera

Olof84 skrev:
Ursäkta att jag hoppar in i denna tråd ett par år senare. Men vad tror ni om denna bcrypt lösning som jag hittade på stackoverflow (se svaret):
http://stackoverflow.com/questions/4795385/how-do-you-use-bcrypt-for-hashing-passwords-in-php

Det verkar som att den funktionen genererar ett eget salt lösenord, vilket kanske är praktiskt?


I praktiken gör den samma sak som min funktion, men den har ett snyggare objektorienterat interface.
Om du vill slippa ge en egen hash kan du lätt lägga till en kontroll som genererar automatiskt om det saknas.

PHP:
1:
<?php function bcrypt($password$salt ''$rounds=12) {
2:
 
3:
    // Kolla om bcrypt är tillgängligt på servern
4:
    if (CRYPT_BLOWFISH != 1) {
5:
        throw new Exception("bcrypt stöds inte. Se http://php.net/crypt");
6:
        return;
7:
    }
8:
 
9:
    // Kolla så rounds är inom tillåtet intervall
10:
    if ($rounds 4)
11:
        $rounds 4;
12:
    else if ($rounds 31
13:
        $rounds 31;
14:
 
15:
    // Skapa ett prefix för att tala om för crypt att vi vill använda Bcrypt
16:
    $salt_prefix sprintf('$2a$%02d$'$rounds);
17:
    
18:
    $salt trim($salt);
19:
    if ($salt == "") {
20:
        $salt microtime(true) . mt_rand();
21:
    }
22:
 
23:
    // Kolla om saltet innehåller ogiltiga tecken:
24:
    if (!preg_match('#^[A-Za-z0-9./]{22}$#'$salt)) {
25:
        // Saltet är inte bcrypt-säkert. Gör om till 22 tecken (A-Za-z0-9./)
26:
        $new_salt base64_encode($salt);
27:
        if (strlen($new_salt) < 22)
28:
            $new_salt .= base64_encode(md5($salt));
29:
        $salt substr($new_salt022);
30:
        $salt str_replace(array('+''-'), '.'$salt);
31:
        $salt str_replace(array('=''_'), '/'$salt);
32:
    }
33:
 
34:
    // hasha lösenordet med bcrypt
35:
    return crypt($password$salt_prefix.$salt);
36:
 
37:
}


Jag la nu till ett default-värde på $salt och om det saknas så slumpas ett salt fram.
 

_________________
"Never argue with stupid people. They will bring you down to their level and beat you with experience."
- Mark Twain
Till toppen på sidan
Visa användarprofil Skicka privat meddelande Besök användarens hemsida
h0tsh0t



Medlem i: 5890 dagar

Status: Offline



#733025
Inlägg Skrivet: 2013-06-17 10:55      Ämne: Citera

Och snart blir det hela ännu enklare i php 5.5 då vi får en inbyggt funktion för bcrypt vilket aldrig är fel Smile
http://se2.php.net/password_hash
 
Till toppen på sidan
Visa användarprofil Skicka privat meddelande
Visa tidigare inlägg:   
Skapa nytt inlägg   Svara på inlägget
PHPportalen Forum Index » Tips och Trix
Hoppa till:  
Du kan inte skapa nya inlägg i det här forumet
Du kan inte svara på inlägg i det här forumet
Du kan inte ändra dina inlägg i det här forumet
Du kan inte ta bort dina inlägg i det här forumet
Du kan inte rösta i det här forumet
Du kan inte bifoga filer i detta forum
Du kan inte ladda ner filer från detta forum
Kontakta oss på adressen: info@phpportalen.net
Webbplatsen bygger i grunden på phpBB © 2001, 2002 phpBB Group

Modifieringar har senare gjorts i systemet av PHPportalen
Sid och logotypdesign skapad av Daren Jularic