PHP: Skripte gegen SQL-Injection absichern
► PHP-Dokumentation: mysqli_escape_string()
SQL-Injection ist ein häufiges Mittel, das es Angreifern ermöglicht, eine Webseite zu hacken. Daher sollte bei der Verwendung von MySQL besonders darauf geachtet werden, dass die PHP-Skripte keine Sicherheitslücken dieser Art enthalten.
Folgendes Skript soll das veranschaulichen:
<?php
$thisfile = basename(__FILE__);
$db_user = "web007"; # Benutzername
$db_password = "g5Rd3dfCvf"; # Benutzerpasswort
$db_name = "usr_web007_1"; # Name der Datenbank
# Verbindung zum Datenbank-Server herstellen
$my = mysqli_connect("localhost", $db_user, $db_password, $db_name)
or die("Keine Verbindung zur Datenbank: ".mysqli_connect_error());
mysqli_set_charset($my, "utf8");
# Datenbanktabelle erzeugen
$sql = "CREATE TABLE IF NOT EXISTS `injection` (
`id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR(30),
`private` SMALLINT UNSIGNED,
`phone` VARCHAR(5)
) CHARSET=utf8";
if (!mysqli_query($my, $sql)) die(mysqli_error($my));
# Datenbanktabelle befüllen
if (!mysqli_num_rows(mysqli_query($my, "SELECT `id` FROM `injection`"))) {
$data = [
["Hans", 0, "71123"],
["Tine", 0, "74532"],
["Hugo", 0, "90872"],
["Ines", 0, "00453"],
["Olaf", 0, "16539"],
["Vera", 1, "44633"],
["Toni", 1, "95562"],
["Mona", 1, "78786"v
["Otto", 1, "24322"],
["Nora", 1, "08773"],
];
foreach ($data as $d) {
$sql = "INSERT INTO `injection` (`name`, `private`, `phone`) VALUES (
'".mysqli_escape_string($my, $d[0])."',
".$d[1].",
'".mysqli_escape_string($my, $d[2])."'
)";
if (!mysqli_query($my, $sql)) die(mysqli_error($my));
}
}
# Ausgabe
header("Content-Type: text/html; charset=utf-8");
echo "<!DOCTYPE html>
<html lang='de'>
<head>
<title>SQL-Injection</title>
<meta charset='UTF-8'>
</head>
<body>
<h3>Öffentliche Einträge:</h3>
<p>\r\n";
$res = mysqli_query($my, "SELECT * FROM `injection` WHERE `private` = '0'");
if (mysqli_num_rows($res)) {
while ($ds = mysqli_fetch_array($res)) {
echo " <a href='".$thisfile."?show=".$ds['id']."'>".$ds['name']."</a></br>\r\n";
}
} else die(mysqli_error());
echo " </p>\r\n";
# Individuellen Eintrag anzeigen
if (isset($_GET['show'])) {
$id = $_GET['show'];
//$id = mysqli_escape_string($my, $_GET['show']);
$sql = "SELECT * FROM `injection` WHERE `private` = '0' AND `id` = '".$id."'";
$res = mysqli_query($my, $sql);
if (mysqli_num_rows($res) && $ds = mysqli_fetch_array($res)) echo " <p><b>".$ds['name'].": Telefon ".$ds['phone']."</b></p>\r\n";
else echo " <p><mark>Der Eintrag ist nicht verfügbar!</mark></p>\r\n";
}
echo "<p>Die privaten Einträge 6-10 können sichtbar gemacht werden, in dem man den Wert von <samp>show</samp> durch <samp>x</samp> ersetzt und an die URL folgenden SQL-Code anhängt:<br><samp>'+OR+id+=+'x</samp><br>wobei <samp>x</samp> die ID des gewünschten Eintrags ist.</p>";
echo" </body>
</html>";
?>
Die privaten Einträge 6-10 können sichtbar gemacht werden, indem man den Wert von show durch x ersetzt und an die URL folgenden SQL-Code anhängt:
'+OR+id+=+'x
wobei x die ID des gewünschten Eintrags ist.
Durch Entfernen des Kommentarzeichens // in Zeile 68 wird der SQL-Befehl mit der Funktion mysqli_escape_string() vor SQL-Injection geschützt.
Ebenso sollte man alle alphanumerische Werte in SQL-Befehlen mit dieser Funktion vorbereiten, da damit bestimmte Sonderzeichen escapet werden, um Syntaxfehler zu vermeiden (s. Zeilen 37 und 39).