Der Ordner seed ist zu erstellen und mit Schreibrechten zu versehen. Ferner ist eine Benutzerdatenbank anzulegen. Einen Download findet ihr im Forum.
Vom Forum könnt ihr auch die benötigte md5.js beziehen.
Hinweise wie ihr euer Login noch sicherer machen könnt:
- um gegen Bruteforce gewappnet zu sein, sperrt die IP Adresse des Clients nach 3 erfolglosen Login-Versuchen
- löscht die Seed Dateien nach erfolgreicher Authentifizierung oder nach x Minuten
Wie funktioniert das?
Der Server generiert serverseitig ein einmaliges Token mit zufälligen Zeichen (im englischen wird hier oft von einem “Seed” gesprochen). Dieses Token wird anschließend im Browser verwendet um das schon gehashte Passwort noch einmal ein eine neues Hash umzuwandeln. Die Daten werden anschließend an den Server übertragen. Das in der Datenbank gespeicherte Passwort-Hash wird nun auch mit dem Token in ein neues Hash umgewandelt und mit dem vom Browser übertragenen Wert verglichen. Stimmen die beiden Hashwerte überein sind auch die eingegebenen Daten korrekt und der User hat sich authentifiziert.
Wichtig bei dieser Vorgehensweise ist, dass das Token immer nur ein einmaliges Token ist. Bei jeder Anfrage wird das Token neu generiert und ist nur für einen Versuch gültig. So kann ein abgehörtes Hash, was im Browser generiert wurde, nicht noch einmal verwendet werden.
login.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Coder Wiki - Secure AJAX Login
</title>
<script src="md5.js" type="text/javascript">
// javascript md5 encoder originated from <http://pajhome.org.uk/crypt/md5/>
// used under license as outlined at <http://pajhome.org.uk/site/legal.html>
// Copyright (c) 1998 - 2002, Paul Johnston & Contributors
// All rights reserved.
</script>
<script type="text/javascript">
<!--
//author: d0nut at coder-wiki.de
var seed_hash, seed_id;
function ajax(send) {
var req;
try {
req = window.XMLHttpRequest ? new XMLHttpRequest() :
new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {
//Kein AJAX Support
}
req.onreadystatechange = function() {
if ((req.readyState == 4) && (req.status == 200)) {
if(send == 'gethash=true') {
var tmp = req.responseText.split('|');
seed_id = tmp[0];
seed_hash = tmp[1];
} else {
var msg = 'login = '+(req.responseText=='true' ? 'ok' : 'false');
document.getElementById('message').innerHTML = msg;
}
}
}
req.open('POST', 'secure.php');
req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
req.send(send);
}
function getSeed() {
ajax('gethash=true');
}
function loginSeed(username, password) {
if(seed_hash == null || seed_id == null) return;
var hash = hex_md5(hex_md5(password) + seed_hash);
ajax('username='+username+'&hash='+hash+'&id='+seed_id);
return false;
}
//-->
</script>
</head>
<body onload="getSeed()">
<h1>Secure AJAX Login
</h1>
<div id="message"> </div>
<form action="post" onsubmit="return loginSeed(this.username.value, this.password.value);">
Benutzername:
<input type="text" name="username" size="20" /><br />
Passwort:
<input type="password" name="password" size="20" /><br />
</form>
</body>
</html>
secure.php
<?php
//author: d0nut at coder-wiki.de
//Erstellt eine zufällige Zeichenkombination aus Zahlen, Klein- & Großbuchstaben
function generate_seed($length) {
$seed = "";
for($i=0; $i<$length; $i++) {
$seed .=
$array[rand(1,
3)];
}
return $seed;
}
$folder = 'seed';
$user = $_POST['username'];
$pw = $_POST['password'];
//Die Benutzerdatenbank wird im Ordner seed in der Datei user.txt platziert
//Benutzernamen durch Zeilen getrennt, das Passwort jeweils mit einem Tabulator eingerückt
$userdb = $folder.'/userdb.txt';
if($_POST['gethash']) {
$seed_filename = $folder.'/'.$id;
$hash = generate_seed(16);
$handle =
fopen($seed_filename,
'w');
} else if($_POST['username'] && $_POST['hash']) {
$seed_filename = $folder.'/'.$_POST['id'];
die('no hash');
//Es existiert keine Hash Datei mit der übermittelten ID
//Durchsuche die Benutzerdatenbank und schaue nach dem md5 Passwort
foreach($file as $row) {
if($user == $row[0]) {
$pw_result =
trim($row[1]);
break;
}
}
if(md5($pw_result.
$seed) ==
$_POST['hash'])
}
?>
Links