PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : XAMPP Login mit MySQL Datenbank


Bullz
2012-12-11, 13:20:10
Habe ein kleines PHP Programm geschrieben was anfangs nur mit fixen Logindaten funktionierte...

//if($_POST["vn"] == "Hans" && $_POST["pw"] == "bingo")

nun versuche ich das gleiche aber mit einer mysql Datenbank im Hintergrund. Habe eine Datenbank erstellt, leider klappt es nicht . Wer ne Idee an was es liegen könnte ?

<?php session_start();
session_destroy();
$_SESSION = array();
?>
<html>
<body>
<form action ="sc_schutz_b.php" method = "post">
<p><input name="vn" /> Vorname</p>
<p><input type ="password" name = "pw" />Passwort</p>
<p><input type = "submit" /><input type = "reset" /></p>
</form>
</body>
</html>

<?php session_start();
if(isset($_POST["vn"]))
mysql_connect("", "root");
mysql_select_db("firma");
$res = mysql_query("select * from Logindaten");
$dsatz = mysql_fetch_assoc($res);
if($_POST["vn"] == $dsatz["Benutzername"] && $_POST["pw"] == $dsatz["Kennwort"]
//if($_POST["vn"] == "Hans" && $_POST["pw"] == "bingo")
$_SESSION["vn"] = $_POST["vn"];
if(!isset($_SESSION["vn"]))
exit("Kein Zugang <br /><a href='sc_schutz_a.php'>zum Login</a>");


?>
<html>
<body>
<h3>Start-Seite</h3>
<?php
echo "<p>Hallo " . $_SESSION["vn"] . "</p>";
?>


<p><a href="sc_schutz_c.php">Zur beliebigen Seite</a></p>
<p><a href="sc_schutz_a.php">Logoff</a></p>
</body>
</html>

Parse error: syntax error, unexpected '$_SESSION' (T_VARIABLE) in /Applications/XAMPP/xamppfiles/htdocs/sc_schutz_b.php on line 11

esistich
2012-12-11, 13:49:14
Bei

if($_POST["vn"] == $dsatz["Benutzername"] && $_POST["pw"] == $dsatz["Kennwort"]

fehlt die schließende Klammer.

Bullz
2012-12-11, 14:30:03
1.) thx es funktioniert. Ich fresse einen Besen das das klappt ... leider gibst noch einen Hacken... wenn ich von sc_schutz_c.php wieder zur sc_schutz_b.php zurück klicke bekomme ich folgende Fehlermeldung

<?php
session_start();
if(!isset($_SESSION["vn"]))
exit("Kein Zugang<br /><a hef='sc_schutz_a.php'>zum Login</a>");
?>
<html>
<body>
<h3>Start-Seite</h3>
<?php
echo "<p>Hallo " . $_SESSION["vn"] . "</p>";
?>
<p><a href="sc_schutz_b.php">Zur Start-Seite</a></p>
<p><a href="sc_schutz_a.php">Logoff</a></p>
</body>
</html>

Warning: mysql_fetch_assoc() expects parameter 1 to be resource, boolean given in /Applications/XAMPP/xamppfiles/htdocs/sc_schutz_b.php on line 7

2.) Was auch komisch ist. Nur der erste Benutzername Passwort aus meiner MYSQL Datenbank funktionieren. Dachte mir sowieso das ich da eine while Schleife draufpacken muss. Wenn ich aber so mache funktioniert leider überhaupt kein login mehr

while($dsatz = mysql_fetch_assoc($res));
{
if($_POST["vn"] == $dsatz["Benutzername"] && $_POST["pw"] == $dsatz["Kennwort"])
//if($_POST["vn"] == "Hans" && $_POST["pw"] == "bingo")
$_SESSION["vn"] = $_POST["vn"];
}
if(!isset($_SESSION["vn"]))
exit("Kein Zugang <br /><a href='sc_schutz_a.php'>zum Login</a>");

sei laut
2012-12-11, 14:58:20
while($dsatz = mysql_fetch_assoc($res));
Mach mal das Semikolon hinten weg.
Und nutze bitte den Button für PHP Code, machts besser lesbar.

Die andere Fehlermeldung sagt: $dsatz = mysql_fetch_assoc($res); <- dort ist $res=0, weiß aber gerade nicht, wieso.
Mein PHP Wissen ist aber auch eingerostet.

esistich
2012-12-11, 15:40:07
Wenn ich mir deinen Quellcode so anschaue, dann fehlt es dir offensichtlich an PHP Grundwissen. So solltest du z.b. Abstand von den MySQL-Funktionen nehmen und MySQLi (http://php.net/manual/de/book.mysqli.php) oder lieber gleich PDO (http://php.net/manual/de/book.pdo.php) verwenden.


$conn = mysql_connect ( 'localhost', 'root', '' ) ;
$db = mysql_select_db ( 'firma', $conn ) ;
$result = mysql_query ( 'SELECT * FROM Logindaten' ) ;

while ( $row = mysql_fetch_assoc ( $result ) ) {

//

}


Die Prüfung bezüglich der Login Daten, solltest du mit der WHERE-Klausel in deinem Datenbank Statement aufnehmen.


$conn = mysql_connect ( 'localhost', 'root', '' ) ;
$db = mysql_select_db ( 'firma', $conn ) ;

$vn = mysql_real_escape_string ( $_POST [ 'vn' ] ) ;
$pw = mysql_real_escape_string ( $_POST [ 'pw' ] ) ;

$result = mysql_query ( "SELECT * FROM Logindaten WHERE Benutzername = '" . $vn . "' AND Kennwort = '" . $pw . "'", $conn ) ;


Und dann mit einer entsprechenden IF/ELSE Anweisung verarbeiten.


$numRows = mysql_num_rows ( $result ) ;

if ( $numRows > 0 ) {

//erfolgreich

} else {

//fehlgeschlagen

}



Außerdem solltest du den Benutzernamen und das Passwort nochmal als Hash in der Datenbank hinterlegen und diese zur Prüfung verwenden, damit sind keine SQL-Injections mehr möglich, da alle dazu erforderlichen Zeichen gehasht bzw. unschädlich gemacht werden.


$vn = mysql_real_escape_string ( md5 ( $_POST [ 'vn' ] ) ) ;
$pw = mysql_real_escape_string ( md5 ( $_POST [ 'pw' ] ) ) ;

$result = mysql_query ( "SELECT * FROM Logindaten WHERE Benutzername_hash = '" . $vn . "' AND Kennwort_hash = '" . $pw . "'", $conn ) ;

samm
2012-12-11, 20:53:02
Was esistich sagt, plus:

1. Als root ohne passwort auf die DB verbinden zu können, finde ich gefährlich xD Erstens bitte PW setzen für den, und zweitens einen spezifischen user verwenden, der nur genau die über die benötigten Rechte verfügt. Sichert ein wenig, falls doch ein SQL-injection-Türchen offen gelassen wurde oder nicht nur von localhost aus auf die DB zugegriffen werden kann.

2. Das Passwort in der Tabelle Logindaten (also nicht das DB-Passwort, sondern das für den Web-Login) ohnehin nur gehasht speichern, aber nicht mit md5 sondern am bequemsten und wesentlich sicherer mit der neuen crypt()-Funktion mit salt und rounds. Macht Account-Hacking wesentlich unbequemer :)

sei laut
2012-12-11, 23:13:49
Das ist doch sicher nur Spielerei und wird nie online gehen. (merkt man schon am Einsatz von XAMPP) Von daher würde ich die Anforderungen runterschrauben. :D

universaL
2012-12-13, 16:10:11
Außerdem solltest du den Benutzernamen und das Passwort nochmal als Hash in der Datenbank hinterlegen und diese zur Prüfung verwenden, damit sind keine SQL-Injections mehr möglich, da alle dazu erforderlichen Zeichen gehasht bzw. unschädlich gemacht werden.


hmm hashing als gegenmittel für sql-injection ist schon etwas abenteuerlich meiner Meinung nach. Passwort sollte man hashen, und zwar nicht mit md5/sha1 sondern mit einer "langsamen"-Hashfunktion wie zum Beispiel bcrypt.

Gegen SQL-Injektion helfen aber prepared-statements. Da ich keinerlei Ahnung von PHP habe, hier einfach ein Stackoverflow link dazu: http://stackoverflow.com/questions/60174/how-to-prevent-sql-injection

esistich
2012-12-14, 01:34:09
hmm hashing als gegenmittel für sql-injection ist schon etwas abenteuerlich meiner Meinung nach.


Eine SQL-Injection wie z.B.

" OR 1=1 #

welche anstelle des Benutzernamens eingegeben wird, richtet keinen Schaden an wenn es vorher verschlüsselt wird.

So ist...
14cec6dcf4b469278482f93b63897fe9
das MD5 Äquivalent zur obigen SQL-Injection und somit unschädlich.

Das setzt natürlich voraus, dass sowohl das Passwort als auch der Benutzername zum Klartext noch mal in verschlüsselter Form in der Datenbank abgelegt wird, was ja kein Problem ist.

Das sieht dann so aus


----------------------------------------------------------------------------------------------
| benutzer | benutzer_hash | passwort |
|----------|----------------------------------|----------------------------------------------|
| hans | f2a0ffe83ec8d44f2be4b624b0f47dde | e8636ea013e682faf61f56ce1cb1ab5c |
----------------------------------------------------------------------------------------------


Geprüft wird benutzer_hash und passwort, indem die übergebenen Werte zum Abgleich ebenfalls verschlüsselt werden.

Passwort sollte man hashen, und zwar nicht mit md5/sha1 sondern mit einer "langsamen"-Hashfunktion wie zum Beispiel bcrypt.

Da scheiden sich die Geister, ich bevorzuge zum Abgleich von Passwörtern eher die schnelleren Algorithmen mit Salt, bcrypt kommt bei mir in anderen Bereichen zum Einsatz.

Die Gefahr liegt nicht in der (Rück)Entschlüsselung sondern durch Abgleichen in Rainbow Tables, was durch den Salt so gut wie unmöglich ist. Außerdem hat die obige Vorgehensweise ja genau den Grund, dass man nicht an die in der Datenbank abgelegten Informationen kommt.

universaL
2012-12-14, 10:56:21
Eine SQL-Injection wie z.B.

" OR 1=1 #

welche anstelle des Benutzernamens eingegeben wird, richtet keinen Schaden an wenn es vorher verschlüsselt wird.
...


in diesem speziellen Fall hast du Recht, aber warum nicht gleich die Antwort geben die es auch für Klartext-Eingaben löst?! Besonders wenn der Empfänger offensichtlich noch nicht allzu erfahren in solchen Dingen scheint.



Da scheiden sich die Geister, ich bevorzuge zum Abgleich von Passwörtern eher die schnelleren Algorithmen mit Salt, bcrypt kommt bei mir in anderen Bereichen zum Einsatz.

Die Gefahr liegt nicht in der (Rück)Entschlüsselung sondern durch Abgleichen in Rainbow Tables, was durch den Salt so gut wie unmöglich ist. Außerdem hat die obige Vorgehensweise ja genau den Grund, dass man nicht an die in der Datenbank abgelegten Informationen kommt.


Besides incorporating a salt to protect against rainbow table attacks, bcrypt is an adaptive function: over time, the iteration count can be increased to make it slower, so it remains resistant to brute-force search attacks even with increasing computation power.


Und ich finde die Geschwindigkeit eines Hashing-Algorithmus ist sehr wohl wichtig. Kann ich Millionen von Passwörtern in der Sekunde ausprobieren, oder sind es vielleicht nur Tausend? Bei Millionen von Passwörtern hilft auch ein Salt nicht mehr wirklich ;-) Das wird hier nun aber ein wenig zu sehr OT.

esistich
2012-12-14, 12:14:29
in diesem speziellen Fall hast du Recht, aber warum nicht gleich die Antwort geben die es auch für Klartext-Eingaben löst?! Besonders wenn der Empfänger offensichtlich noch nicht allzu erfahren in solchen Dingen scheint.

Das war nur eine Empfehlung, da ich sowohl die Klartext als auch die Hash Variante gepostet habe, verstehe ich die Frage jetzt nicht.



Und ich finde die Geschwindigkeit eines Hashing-Algorithmus ist sehr wohl wichtig. Kann ich Millionen von Passwörtern in der Sekunde ausprobieren, oder sind es vielleicht nur Tausend? Bei Millionen von Passwörtern hilft auch ein Salt nicht mehr wirklich ;-) Das wird hier nun aber ein wenig zu sehr OT.

Die Verschlüsselung erfolgt nur ein mal bei der Zusammenstellung des Datenbank Statements, weder verlangsamt noch beschleunigt diese Vorgehensweise die Abfrage. Wenn du Millionen Datensätze zu prüfen hast, dann geht die Abfrage sowieso länger als bei ein paar Tausend Datensätzen, ob du jetzt meinpasswort oder 050e4d72c6214f1a058e518bfd93b579 zur Prüfung abschickst ist wurscht.

universaL
2012-12-14, 13:17:02
Das war nur eine Empfehlung, da ich sowohl die Klartext als auch die Hash Variante gepostet habe, verstehe ich die Frage jetzt nicht.


die allgemeine Lösung sind prepared statements. Warum nicht gleich auf diese hinweisen und stattdessen etwas posten was für den Spezialfall passt


Die Verschlüsselung erfolgt nur ein mal bei der Zusammenstellung des Datenbank Statements, weder verlangsamt noch beschleunigt diese Vorgehensweise die Abfrage. Wenn du Millionen Datensätze zu prüfen hast, dann geht die Abfrage sowieso länger als bei ein paar Tausend Datensätzen, ob du jetzt meinpasswort oder 050e4d72c6214f1a058e518bfd93b579 zur Prüfung abschickst ist wurscht.

Es geht darum wieviele Kandidaten du zu einem gegebenen Hash den du irgendwoher bekommen hast in einer gewissen Zeit ausrechnen kannst. Denn das ist der entscheidende Faktor beim Passwort brechen. Wenn der verwendete Algorithmus nicht so schlecht ist, das du ziemlich direkt Kollisionen ausrechnen kannst, wie zum Beispiel bei MD5. Und sha1/2/3 sind nunmal nicht dafür entwickelt worden Passwörter zu verschlüsseln. Da ging es darum möglichst viele Daten in einer gewissen Zeit hashen zu können, um zum Beispiel Dateien überprüfen zu können. Deshalb sollte man definitiv etwas wie bcrypt für Passwörter benutzen, denn das macht es um Größenordnungen schwerer ein Passwort per Bruteforce zu knacken.

esistich
2012-12-14, 15:26:51
die allgemeine Lösung sind prepared statements. Warum nicht gleich auf diese hinweisen und stattdessen etwas posten was für den Spezialfall passt
Ich habe ihm den Rat gegeben von den MySQL Funktionen abzusehen und auf MySQLi oder gleich auf PDO zu setzen. Lies die Beiträge nochmal durch, da hast du offensichtlich was falsch verstanden, denn ich habe nicht irgendetwas gepostet, sondern den Quellcode des TS. Außerdem obliegt es dem Fragesteller wie oder was er macht, du kannst ihn ja wohl schlecht dazu zwingen, ich weiß gar nicht wo da dein Problem ist?!


Es geht darum wieviele Kandidaten du zu einem gegebenen Hash den du irgendwoher bekommen hast in einer gewissen Zeit ausrechnen kannst. Denn das ist der entscheidende Faktor beim Passwort brechen. Wenn der verwendete Algorithmus nicht so schlecht ist, das du ziemlich direkt Kollisionen ausrechnen kannst, wie zum Beispiel bei MD5. Und sha1/2/3 sind nunmal nicht dafür entwickelt worden Passwörter zu verschlüsseln. Da ging es darum möglichst viele Daten in einer gewissen Zeit hashen zu können, um zum Beispiel Dateien überprüfen zu können. Deshalb sollte man definitiv etwas wie bcrypt für Passwörter benutzen, denn das macht es um Größenordnungen schwerer ein Passwort per Bruteforce zu knacken.
Das hat aber nichts mit dem Login zu tun, der beim TS nicht funktioniert, dein Fall bezieht sich nach einer erfolgreichen Attacke, bei dem verschlüsselte Passwörter durch Rainbow Tables entschlüsselt werden sollen, sofern sie gelistet sind. Und jetzt mal im ernst, wenn sich jemand aus deiner Datenbank frei bedient, dann hast du doch offensichtlich andere Probleme als die Wahl der kryptographische Hashfunktion. Aber wie heißt es doch so schön, lange Rede kurzer Sinn, hier mal ein salted MD5 Hash, der aus einer Zahl zwischen 0 und 99 besteht, zeig mal wie einfach das ist.


8417b724b1df3f331603ec60cafb5036

universaL
2012-12-14, 16:04:15
Ich habe ihm den Rat gegeben von den MySQL Funktionen abzusehen und auf MySQLi oder gleich auf PDO zu setzen. Lies die Beiträge nochmal durch, da hast du offensichtlich was falsch verstanden, denn ich habe nicht irgendetwas gepostet, sondern den Quellcode des TS. Außerdem obliegt es dem Fragesteller wie oder was er macht, du kannst ihn ja wohl schlecht dazu zwingen, ich weiß gar nicht wo da dein Problem ist?!


Ich finde einfach nur das man "Anfängern" nicht Speziallösungen anbieten sollte, sondern Hinweise auf zum Beispiel "prepared statements", die etwas allgemeingültiger sind. Deinen Hinweis auf MySQLi/PDO hab ich wohl tatsächlich überlesen, das tut mir Leid.

Die restliche Diskussion lief denke ich nur zwischen uns beiden ab, und ist wohl ziemlich losgelöst von der Frage des TS, deshalb auch der vorherige Hinweis, das es nun etwas offtopic wird.


Das hat aber nichts mit dem Login zu tun, der beim TS nicht funktioniert, dein Fall bezieht sich nach einer erfolgreichen Attacke, bei dem verschlüsselte Passwörter durch Rainbow Tables entschlüsselt werden sollen, sofern sie gelistet sind. Und jetzt mal im ernst, wenn sich jemand aus deiner Datenbank frei bedient, dann hast du doch offensichtlich andere Probleme als die Wahl der kryptographische Hashfunktion. Aber wie heißt es doch so schön, lange Rede kurzer Sinn, hier mal ein salted MD5 Hash, der aus einer Zahl zwischen 0 und 99 besteht, zeig mal wie einfach das ist.


8417b724b1df3f331603ec60cafb5036


Ich habe keine Ahnung wie man praktisch MD5-Kollisionen ausrechnet, ich habe jetzt auch keine Lust mir das anzulesen, aber ich finde das MD5 kein sinnvoller Algorithmus für Passwort-Hashing ist, ob mit oder ohne Salts. Ohne den folgenden Artikel komplett gelesen zu haben, gibt er denke ich doch eine Idee von dem was ich eigentlich meine.

http://www.heise.de/security/artikel/Passwoerter-unknackbar-speichern-1253931.html

Da mich das doch noch etwas interessiert hat, hab ich in Ruby mal ein kleines Beispiel zusammengebastelt, was zeigt was ich meine:


require 'rubygems'
require 'bcrypt'
require 'securerandom'
require 'digest/md5'
require 'benchmark'

class PasswordChecking

attr_reader :salt, :magic_number, :md5_password, :bcrypt_password

def initialize
@salt = SecureRandom.base64
@magic_number = SecureRandom.random_number(1000)
@md5_password = Digest::MD5.hexdigest("#{salt}#{magic_number}")
@bcrypt_password = BCrypt::Password.create(magic_number)
end

def benchmark
puts Benchmark.measure { find_md5_password }
puts Benchmark.measure { find_bcrypt_password }
end

private

def find_md5_password
1.upto 1000 do |i|
return i if self.md5_password == Digest::MD5.hexdigest("#{self.salt}#{i}")
end
end

def find_bcrypt_password
1.upto 1000 do |i|
return i if self.bcrypt_password == i
end
end

end

PasswordChecking.new.benchmark



md5: 0.000000 0.000000 0.000000 ( 0.000154)
bcrypt: 3.210000 0.000000 3.210000 ( 3.213346)
md5: 0.000000 0.000000 0.000000 ( 0.000665)
bcrypt: 14.290000 0.010000 14.300000 ( 14.324198)

esistich
2012-12-14, 18:36:36
Wie gesagt, da scheiden sich halt die Geister, ich halte salted MD5/SHAx für ausreichend. Welche Methode man letztendlich verwendet, bleibt jedem selbst überlassen. Mir ging es nur darum, mögliche SQL-Injections zu verhindern.