Bitte warten...

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:

Code kopieren
<?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).