mysqli_prepare und htmlspecialchars

SebiPuck

Erfahrenes Mitglied
Hey,
Ich habe eine Frage:
Ich verwende mysqli mit PHP 5 und verstehe nicht, warum es so ein großer Fehler sein sollte (habe ich schon öfters gelesen), wenn man htmlspecialchars vor dem Abspeichern in der DB verwendet.

Weiters habe ich es selbst versucht, eine Injection durchzuführen, das geht aber nicht, obwohl ich keine Vorbereitung o.Ä. vor dem SQL Script verwende.
Ein Script sieht bei mir ca. so aus:
$sql = "SELECT * FROM database WHERE user='HANS'";

Nochmal: Ich nutze mysqli.

Was ich wissen will:
1) WARUM darf ich kein / sollte ich kein htmlspecialchars VOR dem Abspeichern in die Datenbank verwenden
2) Brauche ich zwingend noch ein prepare Statement vor dem Sql Part und wenn ja WARUM, wenn ne Injection eh nicht hin haut ...

Den Link zur Seite poste ich logischer Weise nicht :D
Danke im Voraus,
LG
 
Hi SebiPuck,

vorweg Glückwunsch zum 400.000ten Thread des Forums ;)

zu deinen Fragen:
1) Du darfst das natürlich, aber es ist nicht gerne gesehen. Die Daten in der Datenbank sollten soweit wie möglich 1:1 den Eingaben des Benutzers entsprechen. Möglichst roh, dann kann man danach auch gut damit arbeiten und du verschwendest auch keinen Speicherplatz. Wenn du zum Beispiel später eine andere Schnittstelle zu der Datenbank baust, wie einen Rich-Client, dann müsstest du auf diesem die Daten wieder un-escapen da er ja kein HTML kennt und in der "Oberfläche die Daten falsch anzeigt."
2) Ja, ich würde für jede Abfrage, die User-Input beinhalten kann ein prepare machen. Stichwort ist SQL-Injection, was du ja anscheinend schonmal gehört hast. Wenn deine Anfrage den user dynamisch hat, dann kannst du zum Beispiel statt "HANS" folgende Abfrage provizieren:

SELECT * FROM login WHERE user = 'admin' AND passwort = '' OR 1=1; --';

Mit dieser Abfrage könnte man sich als Admin anmelden, ohne das Passwort zu kennen.
Noch extremere Beispiele gibt es bei anderen Programmiersprachen / Datenbanksysteme, bei denen könntest du auch folgendes ausführen:

SELECT * FROM login WHERE user = 'admin' AND passwort = ''; DROP DATABASE xyz; CREATE USER ....... --';

Mit einem Prepare und Paramtern in der Query kann dir bei obigen Eingaben nichts passieren, da sich die Schnittstelle daraum kümmert dass die Daten richtig und sauber gesichert sind.

Grüße,
BK
 
Okey, vielen dank erst mal ! :)
Das mit dem 400000ten Post dachte ich mir auch schon :D

Ich habe das Ding jetzt mal so abgesichert:

Code:
if(isset($_POST["user"]) && isset($_POST["password"])){
                       
                        $username = $_POST["user"];
                        $password = md5($_POST["password"]);
                        $conn = new mysqli("$host", "$user", "$pass", "$db");
                       
                       
                       
                           /* Create a prepared statement */
                           if($stmt = $conn -> prepare("SELECT ingame, password FROM login WHERE ingame=? AND password=?")) {

                              /* Bind parameters
                                 s - string, b - blob, i - int, etc */
                              $stmt -> bind_param("ss", $username, $password);

                              /* Execute it */
                              $stmt -> execute();

                              /* Bind results */
                              $stmt -> bind_result($result);

                              /* Fetch the value */
                              $stmt -> fetch();

                              /* Close statement */
                              $stmt -> close();
                           }
                       
                        $sql = "SELECT ingame, password FROM login WHERE ingame='$username' AND password='$password'";
                        $result = $conn->query($sql);
                       
                        if (mysqli_num_rows($result) != 0) {
                       
                            $_SESSION["user"] = $username;
                           
                            $error = "Du hast dich erfolgreich angemeldet";
                           
                            //renew user's skin (delete avatar in cache - folder
                            $filename = 'tools/cache/'.$username.'.png';
                            if (file_exists($filename)) {
                                unlink("$filename");
                            }

                            header('Location: account/');
                        }else{
                            $error = "Dein Username oder dein Password nicht korrekt !";
                        }

                        $conn->close();
                    }

Stimmt das so :)
Vielen Dank im Voraus,
LG
 
Ich sehe kein Injection den du ausprobiert hast.
Prepared mach Sinn, wenn du PHP-Variablen übergeben willst. Dein SQL ist ein String ohne einfluss von anderstwo. Dann macht Prepare keinen Sinn. Wenn hingegen 'HANS' in einer Variable ist, dann macht es Sinn.

Mit Prepared braucht man mWn kein Escape mehr, da Prepared Statements nicht einfach ein SQL-String generiert.
 
Sorry, das obrige Beispiel ist falsch, da hatte ich auch noch die alte Abfrage drin :)

Code:
if(isset($_POST["user"]) && isset($_POST["password"])){
                       
                        $username = $_POST["user"];
                        $password = md5($_POST["password"]);
                        $conn = new mysqli("$host", "$user", "$pass", "$db");
                       
                       
                       
                           /* Create a prepared statement */
                           if($stmt = $conn -> prepare("SELECT ingame, password FROM login WHERE ingame=? AND password=?")) {

                              /* Bind parameters
                                 s - string, b - blob, i - int, etc */
                              $stmt -> bind_param("ss", $username, $password);

                              /* Execute it */
                              $stmt -> execute();

                              /* Bind results */
                              $stmt -> bind_result($result);

                              /* Fetch the value */
                              $stmt -> fetch();

                              /* Close statement */
                              $stmt -> close();
                           }
                       
                        if (mysqli_num_rows($result) != 0) {
                       
                            $_SESSION["user"] = $username;
                           
                            $error = "Du hast dich erfolgreich angemeldet";
                           
                            //renew user's skin (delete avatar in cache - folder
                            $filename = 'tools/cache/'.$username.'.png';
                            if (file_exists($filename)) {
                                unlink("$filename");
                            }

                            header('Location: account/');
                        }else{
                            $error = "Dein Username oder dein Password nicht korrekt !";
                        }

                        $conn->close();
                    }

@Yaslaw ich verstehe nicht ganz, was du mir damit sagen willst,
LG
 
Er sagt, dass der ganze Injection-Schutz nicht nötig ist,
wenn in der SQL-Abfrage keine Variablen (vom User eingegeben etc.) vorkommen.

Zum Code:
MD5 ist böse. Weg damit.
Und wenn das prepare nicht funktioniert hat sollte man auch keine Zeilenanzahl abfragen...

Und dass Injections funktionieren kannst du uns gern glauben. Ich durfte schon einmal
einem zweifelnden User vorführen, alle Passwörter seiner Datenbank ändern zu können;
kann ich auf Wunsch gern wiederholen :D
 
Hey, das is mir schon klar, dass ich kein prepare brauche, wenn der User nicht an der Abfrage selbst beteiligt ist :D
MD5 ist böse, ich weiß, das ganze ist nur zu Testzwecken da, früher oder sp#ter werd ich die passenden PHP Funktionen dafür verwenden :)

Vielen dank für die Hilfe :)
LG
 
Zurück