inloggen met zout
Ik logde altijd in met een query zoals hieronder zonder zout :(
Quote:
$qry = '
select
l.id,
l.login,
schermnaam,
hash
from
logins l
where
l.login = "' . mysqli_real_escape_string($con, $_POST['email']) . '" and
(hash="' . hash('sha512', $_POST['pw']) . '") and
true
';
select
l.id,
l.login,
schermnaam,
hash
from
logins l
where
l.login = "' . mysqli_real_escape_string($con, $_POST['email']) . '" and
(hash="' . hash('sha512', $_POST['pw']) . '") and
true
';
Ik zou echter de veiligheid willen verhogen en ook de salt bijvoegen.
Ik weet password_verify en password_hash maar zie niet onmiddellijk hoe te implementeren in de inlogquery.
De wachtwoord wijzigenquery, OK dat kan maar inloggen?
Hoe doen jullie dat?
Wat gebruiken jullie zoal als zout? Woorden, afkortingen, speciale tekens, het systeem(de functie) zelf laten aanmaken, zelf iets maken via random generator?
Hoe zonder zout converteren naar met zout zonder veel last voor de gebruikers?
Jan
Code (php)
1
2
3
4
5
6
7
2
3
4
5
6
7
$i = 10;
$salt = bin2hex( openssl_random_pseudo_bytes( $i, $cstrong ) );
$salted = $salt . '_' . $password;
$md5Pass = md5( $salted );
$hashPass = password_hash( $salted, PASSWORD_BCRYPT);
$gostPass = hash( 'gost', $salted );
$salt = bin2hex( openssl_random_pseudo_bytes( $i, $cstrong ) );
$salted = $salt . '_' . $password;
$md5Pass = md5( $salted );
$hashPass = password_hash( $salted, PASSWORD_BCRYPT);
$gostPass = hash( 'gost', $salted );
Meer info :
https://crackstation.net/hashing-security.htm
Weet dat password_hash al een salt van zichzelf heeft. Je hoeft dat dus niet extra toe te voegen, tenzij je paranoide bent.
En een gebruiker staat daar buiten.
Waarom de lijn $md5Pass = md5( $salted );? Daarna doe je niets meer met $md5Pass.
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<?php
// Komt van webpagina
$_POST['naam'] = 'Bakker Bart';
$_POST['plaats'] = 'Hindelopen';
$_POST['username'] = 'Dirk';
$_POST['password'] = 'wachtwoord';
// Aanmelden/Registreren verwerken
$naam = $_POST['naam'];
$plaats = $_POST['plaats'];
$username = $_POST['username'];
$password = $_POST['password'];
// Toevoegen database
$i = 10;
$salt = bin2hex( openssl_random_pseudo_bytes( $i, $cstrong ) );
$salted = $salt . '_' . $password;
$hash = md5( $salted ); // of een ander hash algoritme
$query = "INSERT INTO leden ( naam, plaats, username, salt, hash ) VALUES ( '$naam', '$plaats', '$username', '$salt', '$hash' )";
// Opvragen bij login
$query = "SELECT naam, plaats, username, salt, hash FROM leden WHERE username = '$username'";
// dan data controleren
if( $row->hash == md5( $row->salt . '_' . $password ) )
{
// ga verder
} else {
// fout
}
// ....
?>
// Komt van webpagina
$_POST['naam'] = 'Bakker Bart';
$_POST['plaats'] = 'Hindelopen';
$_POST['username'] = 'Dirk';
$_POST['password'] = 'wachtwoord';
// Aanmelden/Registreren verwerken
$naam = $_POST['naam'];
$plaats = $_POST['plaats'];
$username = $_POST['username'];
$password = $_POST['password'];
// Toevoegen database
$i = 10;
$salt = bin2hex( openssl_random_pseudo_bytes( $i, $cstrong ) );
$salted = $salt . '_' . $password;
$hash = md5( $salted ); // of een ander hash algoritme
$query = "INSERT INTO leden ( naam, plaats, username, salt, hash ) VALUES ( '$naam', '$plaats', '$username', '$salt', '$hash' )";
// Opvragen bij login
$query = "SELECT naam, plaats, username, salt, hash FROM leden WHERE username = '$username'";
// dan data controleren
if( $row->hash == md5( $row->salt . '_' . $password ) )
{
// ga verder
} else {
// fout
}
// ....
?>
Gewijzigd op 14/06/2022 11:17:09 door Adoptive Solution
Na ophalen van het record moet ik nog steeds de hash controleren. Dat was echter wat ik net probeerde te vermijden. Mijn query controleert in 1 beweging wachtwoord en login en dat wou ik behouden. Mogelijks is dit onmogelijk.
PS Ik werk momenteel met bedrijfscomputer en vermelde site https://crackstation.net/hashing-security.htm is verboden!
Jan
Code (php)
1
2
3
4
5
6
7
2
3
4
5
6
7
<?php
$query = "SELECT naam, plaats, username, salt, hash
FROM leden
WHERE username = '$username'
AND MD5(CONCAT(salt, '_', '$password') = hash
";
?>
$query = "SELECT naam, plaats, username, salt, hash
FROM leden
WHERE username = '$username'
AND MD5(CONCAT(salt, '_', '$password') = hash
";
?>
Maar de vraag is of je database dan wel zo slim is om dat te optimaliseren en alleen voor dat ene record met username = '$suername' de hash te bepalen en niet voor alle 10.000 records in je database.
Ik ga dan toch maar werken met de password_verify en controleren via php. Sinds php 8.0 gebruikt deze standaard zijn eigen zoutvaatje.
Ik stel wel vast dat de lengte veel kleiner is dan via hash('sha512', $_POST['pw']). Slechts 60 of 97 ipv 128 en bevat ook nog de salt. Is dit dan nog wel veilig denk ik dan.
Welke hash zou ik het best gebruiken?
PASSWORD_DEFAULT, PASSWORD_BCRYPT, PASSWORD_ARGON2I of PASSWORD_ARGON2ID en eventuele extra opties. Ik wil een goede beveiliging :)
Jan
Het toont alle hashes men hun lengte.
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<h3>Hash lengte</h3>
<pre>
<?php
$data = $salted;
$r = crypt( $data );
printf("%-12s %3d %s\n", 'crypt', strlen($r), $r);
$r = password_hash( $data, PASSWORD_BCRYPT );
printf("%-12s %3d %s\n", 'bcrypt', strlen($r), $r);
foreach ( hash_algos() as $v )
{
$r = hash( $v, $data, false );
printf("%-12s %3d %s\n", $v, strlen($r), $r);
}
?>
</pre>
<pre>
<?php
$data = $salted;
$r = crypt( $data );
printf("%-12s %3d %s\n", 'crypt', strlen($r), $r);
$r = password_hash( $data, PASSWORD_BCRYPT );
printf("%-12s %3d %s\n", 'bcrypt', strlen($r), $r);
foreach ( hash_algos() as $v )
{
$r = hash( $v, $data, false );
printf("%-12s %3d %s\n", $v, strlen($r), $r);
}
?>
</pre>
En dit kan je apart gebruiken of ook toevoegen.
Het rekent uit hoe lang een hash algo erover doet.
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
<pre>
<?php
$curTime = microtime(true);
echo 'Building random data ...' . PHP_EOL;
@ob_flush();flush();
$data = '';
for ($i = 0; $i < 64000; $i++)
$data .= hash('md5', rand(), true);
echo strlen($data) . ' bytes of random data built !' . PHP_EOL . PHP_EOL . 'Testing hash algorithms ...' . PHP_EOL;
@ob_flush();flush();
$results = array();
$v = 'crypt';
echo $v . PHP_EOL;
@ob_flush();flush();
$time = microtime(true);
crypt( $data );
$time = microtime(true) - $time;
$results[$time * 1000000000][] = "$v ( crypt() )";
$v = 'bcrypt';
echo $v . PHP_EOL;
@ob_flush();flush();
$time = microtime(true);
password_hash( $data, PASSWORD_BCRYPT );
$time = microtime(true) - $time;
$results[$time * 1000000000][] = "$v ( password_hash() )";
$v = 'md5';
echo $v . PHP_EOL;
@ob_flush();flush();
$time = microtime(true);
md5( $data );
$time = microtime(true) - $time;
$results[$time * 1000000000][] = "$v ( md5() )";
foreach (hash_algos() as $v) {
echo $v . PHP_EOL;
@ob_flush();flush();
$time = microtime(true);
hash($v, $data, false);
$time = microtime(true) - $time;
$results[$time * 1000000000][] = "$v (hex)";
$time = microtime(true);
hash($v, $data, true);
$time = microtime(true) - $time;
$results[$time * 1000000000][] = "$v (raw)";
}
ksort($results);
echo PHP_EOL . PHP_EOL . 'Results: ' . PHP_EOL;
$i = 1;
foreach ($results as $k => $v)
foreach ($v as $k1 => $v1)
echo ' ' . str_pad($i++ . '.', 4, ' ', STR_PAD_LEFT) . ' ' . str_pad($v1, 30, ' ') . ($k / 1000) . ' microseconds' . PHP_EOL;
?>
</pre>
<?php
echo '<p>Begintijd : ' . $curTime . '<br />';
echo 'Eindtijd : ' . microtime(true) . '<br />';
$timeConsumed = round(microtime(true) - $curTime,3);
echo 'Duur : ' . $timeConsumed . '</p>';
$d = date("H:i:s.u", microtime(true) - $curTime );
echo $d;
?>
<?php
$curTime = microtime(true);
echo 'Building random data ...' . PHP_EOL;
@ob_flush();flush();
$data = '';
for ($i = 0; $i < 64000; $i++)
$data .= hash('md5', rand(), true);
echo strlen($data) . ' bytes of random data built !' . PHP_EOL . PHP_EOL . 'Testing hash algorithms ...' . PHP_EOL;
@ob_flush();flush();
$results = array();
$v = 'crypt';
echo $v . PHP_EOL;
@ob_flush();flush();
$time = microtime(true);
crypt( $data );
$time = microtime(true) - $time;
$results[$time * 1000000000][] = "$v ( crypt() )";
$v = 'bcrypt';
echo $v . PHP_EOL;
@ob_flush();flush();
$time = microtime(true);
password_hash( $data, PASSWORD_BCRYPT );
$time = microtime(true) - $time;
$results[$time * 1000000000][] = "$v ( password_hash() )";
$v = 'md5';
echo $v . PHP_EOL;
@ob_flush();flush();
$time = microtime(true);
md5( $data );
$time = microtime(true) - $time;
$results[$time * 1000000000][] = "$v ( md5() )";
foreach (hash_algos() as $v) {
echo $v . PHP_EOL;
@ob_flush();flush();
$time = microtime(true);
hash($v, $data, false);
$time = microtime(true) - $time;
$results[$time * 1000000000][] = "$v (hex)";
$time = microtime(true);
hash($v, $data, true);
$time = microtime(true) - $time;
$results[$time * 1000000000][] = "$v (raw)";
}
ksort($results);
echo PHP_EOL . PHP_EOL . 'Results: ' . PHP_EOL;
$i = 1;
foreach ($results as $k => $v)
foreach ($v as $k1 => $v1)
echo ' ' . str_pad($i++ . '.', 4, ' ', STR_PAD_LEFT) . ' ' . str_pad($v1, 30, ' ') . ($k / 1000) . ' microseconds' . PHP_EOL;
?>
</pre>
<?php
echo '<p>Begintijd : ' . $curTime . '<br />';
echo 'Eindtijd : ' . microtime(true) . '<br />';
$timeConsumed = round(microtime(true) - $curTime,3);
echo 'Duur : ' . $timeConsumed . '</p>';
$d = date("H:i:s.u", microtime(true) - $curTime );
echo $d;
?>
Bron : Zie https://www.php.net/manual/en/function.hash.php
En password hash bevatte al voor php 8 zout.
Maar het is me niet zozeer de tijd welke me interesseert. Er logt toch zelden meer dan 1 persoon in terzelfder tijd. De veiligheid is dus veel belangrijker.
password_hash ondersteunt dus slechts 4 mogelijkheden momenteel. Wat zou daarvan dus de beste zijn?
Jan
Gebruik vooral password_hash() en password_verify().
Als je het in één keer wilt kunnen controleren, dan heb je een database nodig die dat ondersteunt, zoals PostgreSQL in combinatie met de extensie pgcrypto. Hiermee kan je direct wachtwoorden controleren die met password_hash() en BCRYPT zijn gemaakt. Een voorbeeld vind je hier: https://stackoverflow.com/questions/55557494/use-pgcrypto-to-verify-passwords-generated-by-password-hash .
"one may take the hash generated by PHP's password_hash, replace the leading $2y$ by $2a$ and pass it as the second argument of pgcrypto's crypt()."
Één van mijn 1° vragen hier op het forum jaren geleden en was ongeveer dezelfde vraag als nu. Toen kreeg ik sha512 als antwoord.
Welke optie zou ik nu moeten kiezen voor de beste veiligheid? PASSWORD_DEFAULT, PASSWORD_BCRYPT, PASSWORD_ARGON2I of PASSWORD_ARGON2ID
Volgens de help kan "standaard" bij elke php versie wijzigen.
De keuze is vooral: mocht er in de toekomst een sterkere encryptie nodig zijn, dan wordt die bij PASSWORD_DEFAULT door PHP geregeld en moet je dat bij PASSWORD_BCRYPT zelf regelen.
Allen bedankt.