De oplossing
We hebben drie onderdelen van ons veilige inlogsysteem:
* formulier
* encryptiesoftware
* server (php, sql, db, jouw feestje)
Ik ga er even van uit dat je je wachtwoorden als volgt opslaat in SQL:
`password` = MD5(SHA1(CONCAT(`username`,':',PLAIN_PWD)))
Dat betekent dat je username en password (PLAIN) samengooit met een ':' ertussen en dan SHA1't en dan MD5't.
Dat zorgt er voor dat `password` voor ELKE user anders is (ook al heeft elke user 'oele' als plain wachtwoord).
Het formulier
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<div><input type="hidden" name="passphrase" id="passphrase" value="" /></div>
<p>Username</p>
<p><input type="text" name="username" id="username" value="user_pass_md5" /></p>
<p> </p>
<p>Password</p>
<p><input type="password" name="password" id="password" value="pindakaas" /></p>
<p> </p>
<input type="submit" value="login" />
</form>
Het inloggen zelf verandert niet. Je vult gewoon je wachtwoord en je username in... En je klikt op login of ramt op enter.
De encryptiesoftware
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<script type="text/javascript" src="/_inc/md5.js"></script>
<script type="text/javascript" src="/_inc/sha1.js"></script>
<script type="text/javascript">
<!--//
var salt = '< ? php echo $_SESSION['js_enc_login']['salt']; ? >';
var do_js_enc = function()
{
$('passphrase').value = hex_md5( $('username').value.toLowerCase() + salt + hex_md5(hex_sha1($('username').value.toLowerCase()+":"+$('password').value)) );
$('password').value = '';
return true;
}
//-->
</script>
md5.js
sha1.js
prototype.js
De server
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
if ( isset($_POST['passphrase'], $_POST['username']) )
{
header("content-type: text/plain");
// print_r( $_POST );
// salt from session (if exists)
$salt = isset($_SESSION['js_enc_login']['salt']) ? $_SESSION['js_enc_login']['salt'] : '';
unset( $_SESSION['js_enc_login']['salt'] );
$sql = "SELECT * FROM js_encryption_login WHERE LOWER(username) = LOWER('" . $_POST['username'] . "') AND LOWER(MD5(CONCAT( LOWER(username), '" . $salt . "', password ))) = LOWER('" . $_POST['passphrase'] . "');";
// echo $sql . PHP_EOL . PHP_EOL;
$qLogin = mysql_query( $sql ) or die(mysql_error());
if ( 1 == mysql_num_rows($qLogin) )
{
echo "LOGIN SUCCESS!!".PHP_EOL;
print_r( mysql_fetch_assoc( $qLogin ) );
}
else
{
echo ":( num_rows: " . mysql_num_rows($qLogin) . PHP_EOL;
}
exit;
}
?>
Zoals je ziet hebben we alleen 'username' en 'passphrase' nodig. Geen 'password'.
Een heel belangrijk onderdeel van de encryptiesoftware is de 'salt'.
Die komt uit een session... Maar wat is het en waar wordt het gemaakt? WAT het is, is weinig interessant. Waar het gemaakt wordt is wel heel belangrijk!!
The salt
2
3
4
5
$_SESSION['js_enc_login']['salt'] = str_shuffle( base64_encode( (string)rand(0,9000000) ) );
?>
Dat moet absoluut NIET VOOR het php process (inloggen). EN absoluut VOOR het formulier (en de scripts).
Zo ziet mijn pagina er uit:
1. het php process (controle op post data, etc)
2. salt maken
3. html openen en scripts (met salt) printen in <head>
4. formulier printen
Het php process gooit de salt weg als ie m heeft opgevangen. Als er geen salt in de session zit, wordt een lege string gebruikt als salt.
Uitleg
Er wordt een salt toegevoegd aan een md5 string die over de lijn gaat als passphrase. Die passphrase bestaat uit username, salt en password.
er staat letterlijk in hoe het password in de database staat. De gehele passphrase:
Hoe het gemaakt wordt is niet spannend. Wat er mee gebeurt ook niet. En dat moet ook niet. Het is onherkenbaar en elke keer anders! Dat is belangrijk! Als een man-in-the-middle DIE string als passphrase zou stelen, kan ie m nog niet gebruiken! Waarom niet? Omdat ie niet weet welke salt erbij hoort... Omdat de salt die erbij hoort op de server staat en niet meegestuurd wordt of als cookie is opgeslagen.
Je kan 100 keer inloggen. 100 keer wordt de salt anders (hoogstwaarschinlijk :)) en dus de passphrase. En dezelfde 100 keer wordt de salt opgevangen en gebruikt in het php process om een zelfde soort passphrase te maken. Die passphrase wordt in SQL gemaakt omdat dat makkelijk is. Je kan ook alle data uit de tabel trekken die bij de user hoort en dan spul gaan vergelijken. Dit is gewoon stuk makkelijk en sneller!
Vragen zijn welkom.
Ik zal proberen het duidelijker uit te leggen als je wilt, maar meer kan ik niet in zo'n tut.
Active example: http://jouwmoeder.nl/projects/js_enc_login/ (de array die geprint wordt na inloggen is wat er in de sql tabel staat voor deze user, het is NIET post data!!)
Source: http://jouwmoeder.nl/projects/js_enc_login/source.php