PHP mit Sicherheit

Sicheres Programmieren – Traue niemals den Eingaben des Benutzers!
Speichern Sie fremde Benutzereingaben nie ohne eine Überprüfung in einer Datenbank oder in einer Datei ab.

Vertrauen Sie keinen Werten, die über Benutzereingaben, dem Formular, der URL oder Cookies in das PHP-Skript gelangen. Alle externen Parameter, selbst wenn diese aus Auswahllisten oder versteckten Feldern kommen, müssen einer Plausibilitätsüberprüfung unterworfen werden, bevor sie im Programm verwendet werden.

Manche Browser wie etwa Safari und Firefox erlauben überdies bereits von Haus aus oder durch Erweiterungen das direkte verändern des Quellcodes. Formular- Manipulationen sind dadurch sogar noch einfacher.

Inhalt dieser Seite:

  1. Validieren – die Datenanalyse
  2. Filtern – das Trennen von Gut und Schlecht
  3. Maskieren – das Entschärfen von Metazeichen

  4. Verzeichnisse und Dateien mit .htaccess sperren
  5. Chmod - Lese- und Schreibrechte vergeben
  6. Sicherheitsoptionen in der php.ini
  7. Passwörter – der Schlüssel zu Ihren Daten

  8. Dateien hochladen – Fremde Daten auf dem Server
  9. CAPTCHAs – Der Schlüssel im Bild
  10. Datei robots.txt – Infos für Webcrawler
  11. Fingerabdruck – Was der Browser verrät

  12. Sicherheitslücke: Fehlermeldungen
  13. Sicherheitslücke: Cross-Site Scripting
  14. Sicherheitslücke: Kontaktformular
  15. Sicherheitslücke: Referrer
  16. Sicherheitslücke: Fremde Inhalte
  17. Sicherheitslücke: Ajax und das XMLHttpRequest
  18. Sicherheitslücke: Datenbank
  19. Sicherheitslücke: Datei-. und Verzeichnisnamen

  20. Halten Sie Ihren Code unter Verschluß
  21. Formular-Spam – Kostenlose Werbung
  22. Formulare – die Fehlerquelle schlechthin

Validieren – die Datenanalyse

Die Validierung ist Teil der Qualitätssicherung und bezeichnet die Prüfung von Werten auf bestimmte Eigenschaften wie etwa, ob der Wert eines bestimmten Datentyps oder eines Datenformats entspricht. Es ist also ein analysierender Vorgang, der als Ergebnis eine Aussage bestätigt oder widerlegt. Solche Eigenschaftsprüfungen könnten mit Fragen wie „entspricht der Wert einer positiven Ganzzahl?“ oder „enthält der Wert keiner Zeichen der Zeichenmenge X?“ ausgedrückt werden.

🖝 Überprüfen ob überhaupt etwas eingegeben wurde:
if (empty($_POST["text"])) { …
if ($_POST["text"] == "") { …

🖝 Stelle Sie sicher das der übergebene Parameter eine Zahl ist und deren Wertebereich, den Sie erwarten, weder unter- noch überschritten wird
if (strlen( $_POST["eingabe"]) < 5) { …

🖝 Überprüfen Sie ob bestimmte Zeichenfolgen in der Benutzereingabe vorhanden sind:
if (strstr($_POST["url"], "http://")) {  oder
if (preg_match('_(<a\s+href\s*=.*){3,}|(http://[a-z0-9-./\_]{6,}.*){2,}_is', $_POST["textarea"])) { …

🖝 Überprüfen Sie auch Zahlen, ob diese sich im erlaubten Bereich befinden und ob tatsächlich eine Zahl eingegeben wurde is_numeric($_POST["zahl"]).

🖝 Weitere Prüfungen: ctype_digit(), is_bool(), is_null(), is_float(), is_int(), is_string(), is_object(), is_array().

🖝 Kürzen Sie Benutzer-Eingaben:
Verlassen Sie sich nicht auf die Begrenzung die im HTML-Attribut: "maxlength" steht:
<input type="text" name="text" size="25" maxlength="30">
Sondern nehmen Sie substr() um die Benutzer-Eingabe konsequent zu kürzen:
$text = substr($_POST["text"], 0, 30);

🖝 Überprüfen Sie das Datum auf Gültigkeit:
if (checkdate($monat, $tag, $jahr)) { …

🖝 Überprüfen auf nur Zahlen:
if (!ctype_digit($_POST["zahl"])) { …

🖝 Überprüfen ob die Benutzer-Eingabe HTML-Code enthält:
if ($_POST["text"] != strip_tags($_POST["text"])) {…

Überprüfen mit Regulären Ausdrücken

🖝 Postleitzahl mit 5 Ziffern:
if (!preg_match("/^\d{5}$/", $_POST["plz"])) { …

🖝 Überprüfen der E-Mail-Adresse auf Gültigkeit:

$_pat = "^[_a-zA-Z0-9-]+(.[_a-za-z0-9-]+)*@([a-z0-9-]{3,})+.([a-za-z]{2,4})$";
 if (preg_match("|$_pat|i", $_POST["email"])) { …

🖝 Überprüfen der URL-Adresse auf Gültigkeit:

$_pat = "#^(http|https)+(://www.)+([a-z0-9-_.]{2,}\.[a-z]{2,4})$#i"
if (preg_match($_pat , $_POST["url"])) { …

🖝 Überprüfen auf nur Zahlen:

 if (preg_match("#^[0-9]+$#", $_POST["zahlen"])) { …

🖝 Überprüfen auf nur Buchstaben:

 if (preg_match("/^[ a-zA-ZäöüÄÖÜß]+$/i", $_POST["buchstaben"])) { …

Filtern – das Trennen von Gut und Schlecht

Das Filtern dient der Trennung von erlaubten und unerlaubten Werten, wobei nur die erlaubten Werte durchgelassen werden. Man sollte sich nicht nur auf gefilterte Eingaben verlassen, sondern auch nochmals beim schreiben in die Datenbank (oder Datei) die Eingaben überprüfen.

🖝 Filtern Sie mit strip_tags($_POST["name"]) HTML-Tags heraus
oder lassen Sie mit preg_match("/[a-zA-Z0-9.äöüÄÖÜß]/", $_POST["name"])
nur bestimmte Zeichen durch.

🖝 Filtern Sie Leerzeichen und Zeilenumbrüche (Metazeichen) am Zeilenanfang und
Zeilenende $text = trim($_POST["text"]);

🖝 Filtern Sie Zeilenumbrüche des Textarea-Tags
$textarea = str_replace(array("\n", "\r"), "", $_POST["textarea"]);

🖝 Filtern einer „E-Mail Header Injection”
preg_replace( '((?:\n|\r|\t|%0A|%0D|%08|%09)+)i' , "", $_POST["email"]);

Weitere Filter

🖝 Filtern einer Variablen durch einen spezifischen Filter filter_var() (PHP 5)
Die eingebauten PHP-Filter repräsentieren, zumindest gegenüber gar keinen Filtern, einen großen Fortschritt, den bisher viele Programmierer noch gar nicht entdeckt haben:

if (! filter_var("test@example.com", FILTER_VALIDATE_EMAIL)) { …

filter_var("www.test.xy", FILTER_VALIDATE_URL)
filter_var($_POST["zahl"], FILTER_VALIDATE_INT)
filter_var($_POST["name"], FILTER_SANITIZE_STRING)

if (!filter_var($_POST["zahl"], FILTER_VALIDATE_INT)) {
 echo 'Keine Zahl eingegeben';
}
$MyInt = filter_var($_POST["zahl"], FILTER_SANITIZE_NUMBER_INT);
// Damit wird alles entfernt, was keine Zahl ist.

FILTER_SANITIZE_EMAIL
FILTER_SANITIZE_ENCODED
FILTER_SANITIZE_MAGIC_QUOTES
FILTER_SANITIZE_NUMBER_FLOAT
FILTER_SANITIZE_NUMBER_INT
FILTER_SANITIZE_SPECIAL_CHARS
FILTER_SANITIZE_STRING
FILTER_SANITIZE_URL
FILTER_UNSAFE_RAW

🖝 Filtern Sie Spam und "schlechte Wörter" durch eigene Funktionen

🖝 Verwenden Sie switch/case wenn Sie eine Navigation oder Datenbank-Anweisungen über $_GET oder per $_POST steuern wollen.

switch ($_GET["do"]) {
 case "del": 
      $do = "delete";
      break;
 case "res":
      $do = "reset";
      break;
 case "edi":
      $do = "edit";
      break;
 default: 
      $do = "none";
}

🖝 Beim Erstellen von Filterfunktionen ist das „Whitelisting” bestimmter Zeichen, also das explizite Zulassen, stets sicherer als das „Blacklisting”, also das explizite verbieten, weil es nur selten gelingt, wirklich alle potenziell problematischen Werte zu erfassen.

$whitelist = array("delete", "reset", "edit");

if (in_array($_GET["do"], $whitelist)) {
 ...
}

🖝 Lassen Sie sich lediglich den reinen Dateinamen mit $_GET übermitteln und setzen den Verzeichnispfad fest in der PHP-Datei ein.

<?php
$verzeichnis = "ein/anderes/verzeichnis/" . basename($_GET["datei"]) . ".php";
if (file_exists($verzeichnis)) {
 include $verzeichnis;
}
?>

🖝 Dateipfad prüfen
if (strpos($_GET['dateiname', '..') { … Überprüfen auf einen Verzeichniswechsel.
if (preg_match("=daten/=", $_GET["dateiname"])) { … Ist das Verzeichnis „daten/” vorhanden.

🖝 Dateipfad, Dateiname und Dateiendung (Extension) ermitteln.

$pfad = pathinfo("/www/htdocs/index.php");
echo $pfad["dirname"] . 
 $pfad["basename"] . 
 $pfad["extension"];

🖝 Inhalte ersetzen - In dem fogenden Beispiel werden deutsche Umlaute ersetzt.

$trans = array("Ö" => "Oe",   "ö" => "oe",   "Ä" => "Ae", 
 "ä" => "ae",   "Ü" => "Ue",   "ü" => "ue",   "ß" => "ss");

$_POST["text"] = strtr($_POST["text"], $trans);

Oder mit str_replace(array("1", "2", "3"), array("eins", "zwei", "drei"), $_POST["text"]);

Maskieren – das Entschärfen von Metazeichen

Das Maskieren bezeichnet das Entwerten von Metazeichen, so dass diese ihre besondere Funktion verlieren. Dies geschieht entweder durch setzen eines zusätzlichen Maskierungszeichens oder durch Ersetzten dieser Zeichen. Das Maskieren ist immer dann notwendig, wenn Werte unbekannten Typs oder Formats (es fand also keine angemessene Validierung oder Filterung statt oder es können immer noch Metazeichen enthalten sein) an ein Subsystem (z.B.: MySQL) übergeben oder an den Client (Browser) ausgegeben werden.

🖝 Mit htmlspecialchars() stellen Sie sicher, dass die Zeichen, die in HTML eine spezielle Bedeutung haben, ordentlich codiert werden, sodass niemand HTML Tags oder JavaScript-Code in Ihre Seite einschmuggeln kann.

echo htmlspecialchars($_POST["name"], ENT_HTML5, 'UTF-8');

🖝 Bauen Sie dazu Maskierungen ein, um Daten in die Datenbank-Tabelle einzutragen; zum Beispiel:
mysqli_real_escape_string($_POST["name"])   (dazu muss eine aktive Verbindung über mysqli_connect() bestehen)!

🖝 Beim eintragen in eine Datenbank mit PDO ("PHP Data Objects" und den Prepared Statements) arbeiten:

$verbindung = new PDO($server, $benutzer, $passwort);

$kommando = $verbindung -> prepare("DELETE FROM `news` WHERE `id` = :id");
$kommando -> bindValue(':id', $_POST["id"]);
if ($kommando -> execute()) { …

Ein aktuelles Beispiel finden Sie unter » Die Daten über ein Formular sicher eintragen (in der Datei: "eintragen.php")

🖝 Bei quotemeta($tring), der Inhalt von $tring wird mit einem Rückstrich
("Backslash", \) vor jedem Vorkommen von . \ + * ? [ ^ ] ( $ ) versehen ("quoten") und zurückgegeben.

🖝 Verwenden Sie beim Datentransport über $_GET die urlencode() / urldecode()-Funktionen.

🖝 Beim eintragen in eine DB-Tabelle (je nach Spaltentyp) mit Hochkommata arbeiten.
… WHERE id='". $_POST["text"] . "'

🖝 Zahlenwert in einen Integer (Datentyp) umwandeln:
$limit = (int) $_POST["limit"]; oder intval($_GET["limit"])
wenn es sich um eine Zahl handelt.

Verzeichnisse und Dateien mit .htaccess sperren

Zugriff auf Dateien sperren (nur include, require, etc. zulassen). Verschieben Sie alle Dateien, die nur über das PHP-Script aufgerufen werden sollen, in ein Verzeichnis. Innerhalb dieses Verzeichnis stellen Sie eine Textdatei mit folgendem Inhalt ein (beim Apache heißt diese Datei „.htaccess”) mit folgender Syntax aus:

<Files .htaccess>
Order Deny,Allow
Deny from all
</Files>

Eigene Fehlerseiten definieren

ErrorDocument 401 http://www.example.com/401.php
ErrorDocument 403 http://www.example.com/403.php
ErrorDocument 404 http://www.example.com/404.php

(401 = Unauthorized, 403 = Forbidden, 404 = File Not Found, » Server Fehlermeldungen und was diese bedeuten)
Oder alle Fehlermeldungen vom Apache einfach zur Startseite weiterleiten. Die Datei „.htaccess” sollte im obersten Verzeichnis ihrer Webpräsenz liegen.

Es kann passieren, dass die Sache nicht funktioniert. Dann hat vielleicht Ihr Provider die Möglichkeit des Anlegens von .htaccess-Dateien auf dem Server unterbunden.

Eine Anleitung finden Sie unter » Fehler 404 mit .htaccess abfangen

Bilder schützen

Bilder / Grafiken und andere Dateien durch das direkte verlinken von anderen Webseiten schützen.
So sind Sie sicher, das Ihre Bilder nicht direkt verlinkt werden und unerwünschter Traffic (Datentransfer) erzeugt wird.

<Files ~ "\.(gif|jpe?g|png|zip)$">
ErrorDocument 403 http://www.example.com/bilder/bilderdieb.png
SetEnvIfNoCase Referer "^http://www.example.com" local_ref=1
SetEnvIfNoCase Referer "^http://example.com" local_ref=1
SetEnvIfNoCase Referer ^$ local_ref=1
Order Allow,Deny
Allow from env=local_ref
</Files>

Das Verzeichnis Ihrer Domain eintragen!

PHP in HTML-Dateien verstecken!

Eine Möglichkeit ist mittels der .htaccess-Direktive so zu konfigurieren, dass dieser verschiedene Dateitypen (zum Beispiel: .htm) durch PHP parst.
 # HTML-Dateien parsen 
 AddType application/x-httpd-php .htm .html 

Sie müssen dann Ihre PHP-Dateien nach den obigen Dateierweiterung umbenennen. Beachten Sie das nicht jeder Provider diese Konfiguration unterstützt.

Verzeichnislisting (Directory Indexing, Verzeichnis-Browsing)

Verzeichnislisting ist eine Funktion des Webservers, die, wenn die übliche Standard-Datei (index.php, index.html, home.html, default.htm) fehlt, automatisch alle Dateien im Verzeichnis zeigt, dann kann das Listing Informationen enthalten, die nicht für die Öffentlichkeit bestimmt sind.

Verzeichnislisting verhindern

DirectoryIndex index.php index.html

A) Fügen Sie in allen Verzeichnissen eine index.php oder index.htm Datei ein.
Inhalt der index-Seite: Entweder ganz normaler Inhalt oder eine Weiterleitung (mit Link, Meta-Tag oder über PHP-header()) zur gewünschten Seite. Somit sind auch Verweise auf Verzeichnisse möglich
(Beispiel: www.example.com/info/image).

B) Sie können in der .htaccess-Datei festlegen, ob der Apache einen Fehler zurückgeben soll, wenn sich keine Startseite in einem Verzeichnis befindet, oder ob er den Inhalt des Verzeichnisses ausgeben soll.

# Inhalt ausgeben:
Options +Indexes
# oder Fehler ausgeben:
Options -Indexes

C) Möglicherweise bietet Ihr Webspace-Provider eine Option an, die es erlaubt Verzeichnislisting abzuschalten.

Chmod - Lese- und Schreibrechte vergeben

Mit dem Befehl Chmod (englisch: change mode) werden im UNIX Umfeld Lese-, Schreib- und Ausführungsrechte von Dateien und Verzeichnisse gesetzt. Viele Webserver, auf denen Ihre Daten liegen, laufen mit UNIX.

Beispiel - Schreibrechte setzen mit PHP: chmod ("/verzeichnis/datei", 0644);

🖝 Durch das falsche setzen von Chmod können unberechtigte Benutzer (vom selben Server) Zugriff auf Ihre Dateien erhalten, beachten Sie diesen Umstand und seien Sie entsprechend vorsichtig. Die Berechtigungen Ihres obersten Verzeichnisses sollten Sie deshalb niemals ändern, bzw. niemals mit vollen Rechten (Chmod 777) versehen. Mit dem „obersten Verzeichnis” ist Ihr Account-Start-Verzeichnis gemeint.
Mehr dazu unter » Schreib- und Zugriffsrechte » CHMOD-Kalkulator (Chmod richtig einstellen)

Sicherheitsoptionen in der php.ini

Ein Feature von PHP zur Erhöhung der Sicherheit ist die Konfiguration von PHP mit register_globals = off. Mit Deaktivierung der Möglichkeit, irgendeine vom Benutzer übertragenen Variable in den PHP Code zu injizieren, können Sie die Anzahl „vergifteter” Variablen reduzieren, welche ein potentieller Angreifer zufügen könnte.

allow_url_fopen = off legt fest, ob man Dateien öffnen kann (z.B. mit fopen()) die nicht auf dem Server liegen.
allow_url_include = off sorgt dafür, dass PHP-Skripte nur lokale Dateien des Servers einbinden können (ab PHP 5.2).
safe-mode = on bewirkt unter anderem, dass der PHP-Prozess nur noch auf Dateien und Verzeichnisse zugreifen darf, die dem Nutzer gehören.
magic_quotes_gpc = onescaped” alle Single-quotes ('), Double quotes (") , Backslashes (\) und NULL-Zeichen automatisch mit einem Backslash.

🖝 phpinfo() Zeigt eine große Anzahl von Informationen über die aktuelle Konfiguration von PHP an. Unter anderem die Optionen während des Kompilierens und die Erweiterungen, die PHP Version, Informationen über den Server, die PHP Umgebung, Version und Informationen zum Betriebssystem, Pfade, Haupt- und lokale Werte der Konfigurationsoptionen.

<?php phpinfo(); ?>

Lassen Sie diesen PHP-Code niemals offen auf einer Seite ausführen!

Passwörter – der Schlüssel zu Ihren Daten

Schützen Sie Ihre Formulareingaben, erlauben Sie Einträge nur über eine Authentifizierung für berechtigte (Passwort-Abfrage).

🖝 Verschlüsseln Sie alle Passwörter die Sie speichern wollen.
$passwort = sha1("Passwort"); oder crypt() Mehr dazu unter: http://php.net/manual/de/function.crypt.php, Wie man mit Pfeffer den Fisch versalzt - Tutorial über das sichere Speichern von Passwörtern

🖝 Verwenden Sie kryptische Passwörter
Eigentlich sollte man das nicht mehr erwähnen müssen: Passwörter für Web- oder Datenbankserver, die Sie in einem Lexikon finden können, sind so gut wie geknackt.
Die „billigsten” Passwörter sind: passwort, password, user, admin, Vorname, Nachname, Name der Homepage, Thema der Homepage, …

🖝 Automatische Texteingabe in Formularfeldern verhindern.
Moderne Browser haben eine autom. Eingabefunktion die schon einmal eingegebene Daten in ein Formularfeld wieder einfügen. Es gibt Situationen, in denen es sinnvoll ist, das automatische ausfüllen zu verhindern, wenn zum Beispiel jemand anderes vor dem PC sitzt.
<form autocomplete="off"> oder direkt im HTML-Tag <input type="text" autocomplete="off"> für ein einzelnes Element.

Dateien hochladen – Fremde Daten auf dem Server

Lässt man dem Besucher die Möglichkeit Dateien hoch zu laden, so muss gewährleistet werden, dass diese Dateien nicht auf das restliche System anwendbar sind. Das funktioniert beispielsweise in dem man nur bestimmte Dateitypen erlaubt. Das Problem ist, dass jemand beispielsweise eine PHP-Datei hochladen könnte um diese dann extern aufzurufen, das würde dazu führen, dass jene Datei auf das restliche System eingreifen könnte.

🖝 Überprüfen des » Mimetypen und der Dateigröße:

if ((($_FILES["file"]["type"] == "image/gif") ||
      ($_FILES["file"]["type"] == "image/jpeg") ||
      ($_FILES["file"]["type"] == "image/png"))
 && ($_FILES["file"]["size"] < 20000)) { …

🖝 Es ist sinnvoll zu prüfen, ob die hoch geladene Datei auch wirklich ein Bild ist. Dafür kann man die Funktion getimagesize() verwenden. Handelt es sich um ein gültiges Bild, gibt die Funktion ein Array mit Informationen über das Bild zurück.

list($width, $height) = getimagesize($_FILES["file"]["tmp_name"]);
if ($width > 0 && $height > 0) {
 echo "Die Datei ist ein Bild!";
}

🖝 Verschieben Sie die hoch geladene Datei in ein anderes Verzeichnis mit begrenzten Schreibrechten (Chmod) und geben Sie der Datei einen neuen Namen. Wenn die Datei nicht direkt aufgerufen werden soll, so schützen Sie das Verzeichnis per .htaccess

🖝 Bieten Sie eine Upload-Möglichkeit möglichst nicht öffentlich für Jedermann an, sondern erlauben Sie das nur über eine Authentifizierung für Berechtigte.

CAPTCHAs – Der Schlüssel im Bild!

(CAPTCHA = Completely Automated Public TuringTest to Tell Computers and Humans Apart) Vor einiger Zeit hat es sich weiträumig durchgesetzt, sog. CAPTCHAs zu verwenden. Hierfür werden fast immer Zahlen oder Wörter möglichst unleserlich in einem Bild dargestellt, das vermeintlich nur von Menschen entziffert werden kann.

➤ Beachten Sie das CAPTCHAs für Menschen mit Sehbehinderung nur schwer oder nicht ausgefüllt werden können, hier sollte auf Barrierefreiheit des Formulars geachtet werden (ReCaptcha).

🖝 Andere Möglichkeiten: Speicherung der IP-Adresse; Speicherung von Cookies;
Ändern des Namens im <input>-Tag; Zeitabhängige eingaben; Rechenaufgabe vom Benutzer ausfüllen lassen; Versteckte Eingabefelder (mit CSS); Einen Bestätigungs-Link per E-Mail senden (Zeitabhängige Aktivierung); Formulare mit AJAX; Formular absenden mit JavaScript … Der Fantasie sind keine Grenzen gesetzt, solange der Besucher mit macht ).

Datei robots.txt – Infos für Webcrawler

Beim Auffinden einer Webseite von einem Webcrawler (automatisches Programm zum indexieren von Links und Seiten auf Webseiten) wird zuerst die Datei „robots.txt” (klein geschrieben) gelesen. In dieser Datei kann festgelegt werden, ob und wie die Webseite von einem Webcrawler besucht werden darf.

Die Datei „robots.txt” ist eine Textdatei in einem einfach lesbaren Format.

# Diese Verzeichnisse/Dateien sollen nicht durchsucht werden
User-agent: *
Disallow: /geheim.php

Ein Ausgrenzen bestimmter Teile einer Webpräsenz durch robots.txt garantiert keine Geheimhaltung. Genauso wenig schützt der Meta-Tag <meta name="robots" content="noindex"> davor.

Fingerabdruck – Was der Browser verrät

Wenn man mit einem Browser im Internet surft, wird meist mehr verraten, als dem Besucher lieb ist. $_SERVER["HTTP_USER_AGENT"]; Beispielsweise: „ Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; +claudebot@anthropic.com) ” Auch diese Infos können via Browser manipuliert werden.

🖝 Richtige Browser sollten immer einen User-Agenten mitschicken, also selbst bekanntgeben, wer sie sind. Ist dies nicht der Fall, ist der Besucher meist ein Bot (Webcrawler).

🖝 Den USER_AGENT Mozilla auszusperren sollte man tunlichst vermeiden, da die meisten Browser sich als Mozilla identifizieren.

Sicherheitslücke: Fehlermeldungen

Lassen Sie PHP oder MySQL-Fehlermeldungen nie im produktiven Einsatz anzeigen. Angreifer gewinnen durch diese Fehlermeldungen hilfreiche Tipps! Anzeige von: Pfad und Name der Datei, Script-Fehler und Zeilennummer. Solange man seinen Quelltext "debuggen" muss (auf Fehler überprüfen), ist dieser Ansatz zu begrüßen, doch sobald die Webseite in der finalen Fassung vorliegt, ist der Einsatz von error_reporting(), mysqli_error(), $db->errorInfo() etc. eher als Sicherheitslücke zu bezeichnen.

🖝 Die folgende Anweisung verhindert, dass Angreifer gezielt Fehlermeldungen provozieren können.
error_reporting(0); Siehe: » Vermeidung von PHP-Fehlermeldungen.

🖝 Kommentare im HTML-Quelltext
Eine Schwachstelle liegt vor, wenn eine Website sensible Daten zum Beispiel Kommentare der Entwickler, die einem Angreifer helfen das System zu missbrauchen, ausgibt.

Sicherheitslücke: Cross-Site Scripting (XSS)

Manipulationen von Formularen ist einfacher als manch einer sich das denkt. Die einfachste Möglichkeit, ein Formular zu manipulieren, ist, den HTML-Quellcode des Formulars zu kopieren und in einer lokalen Datei zu speichern. Diese kann dann beliebig verändert werden. Dadurch ist es auch möglich, dass Schadcode dort injiziert wird, wo es im Originalformular gar nicht möglich war (beispielsweise bei versteckten Formularelementen, Auswahllisten, Checkboxen etc.).

Das superglobale Array $_SERVER beinhaltet verschiedene Informationen über die Ausführungsumgebung und den Server. Sie umfasst unter anderem das Element $_SERVER['PHP_SELF']. Diese global verfügbare, vordefinierte Variable liefert den Dateinamen des jeweiligen Skriptes, welches gerade ausgeführt wird, wie zum Beispiel: echo $_SERVER['PHP_SELF']

🖝 Die einfachste Gegenmaßnahme beim Einsatz von PHP_SELF besteht darin, die Variable immer zu bereinigen.
echo filter_var($_SERVER['PHP_SELF'], FILTER_SANITIZE_STRING); (PHP 5)

🖝 Verwenden Sie anstelle von $_SERVER["PHP_SELF"] besser $_SERVER["SCRIPT_NAME"] oder gleich den Dateinamen.

Sicherheitslücke: Kontaktformular (E-Mail-Header-Injection)

Die "E-Mail-Header-Injection" ist eine Methode, E-Mail-Kopfzeilen über ein Kontaktformular-Skript in eine E-Mail zu "injizieren". Spammer können auf diese Art Kontaktformular-Sendeskripte zum massenhaften Verteilen von Spam missbrauchen. Besonders ärgerlich für den Besitzer des Kontaktformulars ist, dass Spammer seine E-Mail-Adresse als Absender des Spams angeben können.
Ein sicheres Formular können Sie mit dem » Kontaktformular Generator erstellen.

🖝 Gegenmaßnahmen siehe » Filtern – das Trennen von Gut und Schlecht

🖝 Mehrere E-Mails per BCC verschicken
In einer BCC-E-Mail (Blind-Carbon-Copy) finden Viren höchstens zwei E-Mail-Adressen. In einer CC-E-Mail (Carpon-Copy) können es buchstäblich Hunderte von Adressen sein. CC-E-Mails mit vielen E-Mail-Adressen sind ein gefundenes Fressen für Spammer. Mit BCC-E-Mails tragen Sie also einen Beitrag zur Bekämpfung von Spam bei.

Sicherheitslücke: Referrer

Der Refer(r)er ist beliebig manipulierbar aber an sich ungefährlich. Schaden anrichten kann er wenn das Auswertungsscript anfällig z.B. gegen HTML-Injection ist. Manche Webseiten führen irgendwo auf der Seite eine Liste: „verlinkt von” Wenn dort ungeprüft der Referrer verwendet wird kann man einen Referrer in der Art:

<script type="text/javascript">location.href="http://SeiteMitVirus.xy"</script>

einschmuggeln. Und künftig wird jeder Besucher der Seite (sofern Javascript aktiv ist) auf http://SeiteMitVirus.xy umgeleitet.

🖝 Wenn Sie mit dem Referrer arbeiten, dann setzen Sie strip_tags() dazu ein um HTML-Spam im Referrer zu löschen.

🖝 Referrer nicht zu sicherheitsrelevanten Zwecken auf einer Website verwenden.

Sicherheitslücke: Fremde Inhalte

Viele Webseiten haben auf Ihrer Seite Inhalte von anderen Seiten die z.B.: das Wetter, aktuelle News, Werbebanner etc. anzeigen, diese werden oft als JavaScript, Frame, Flash oder XML-Datei bereit gestellt. Der Betreiber hat hier wenig Möglichkeiten um schadhaften Code zu filtern.

🖝 Wenn Sie eine Login-Seite haben, sollten Sie auf die Anzeige fremder Inhalte verzichten.

🖝 CSS und JavaScript binden verlinkte Grafiken auch mit einer anderen Dateiendung ein. background-image: url(datei.php); Was auf der einen Seite nützlich ist kann auch eine Gefahrenquelle sein.

🖝 Um JavaScript zu unterbinden das von einem iFrame-Fenster einer fremden Seite kommt, genügt es das HTML 5 - Attribut sandbox="sandbox" einzufügen.

Sicherheitslücke: Ajax und das XMLHttpRequest

Der Begriff Ajax steht für „Asynchronous Javascript and XML” und bezeichnet ein Konzept der asynchronen Datenübertragung zwischen einem Server und dem Browser. Die Besonderheit dabei ist, dass es damit möglich ist, innerhalb einer HTML-Seite eine HTTP-Anfrage durchzuführen, ohne die Seite komplett neu laden zu müssen.

Die Kombination aus massivem Javascript-Einsatz und Interaktivität bringt zahlreiche Gefahren mit sich, die sowohl für Betreiber als auch Benutzer von Web-2.0-Applikationen fatale Folgen haben können. Über geschickte Eingaben kann ein Angreifer zum Beispiel die Nutzerdatenbank manipulieren, einen Server für längere Zeit lahm legen oder Inhalte verändern.
Auf Deutsch: Sie müssen die empfangenen Daten die über JavaScript kommen validieren.

🖝 JavaScript sollten Sie niemals als Sicherheitsmaßnahme zur Validierung der Formulareingabe nutzen, weil diese Methode leicht ausgehebelt werden kann. Verwenden Sie JavaScript nur um den Benutzer auf seine Fehler im Formular hinzuweisen.

Sicherheitslücke: Datenbank

SQL Injectionen gehören zu den gefährlichsten und weitverbreitesten Fehlern bei Webanwendungen. Besondere Bedeutung fällt dabei der Datenbank „MySQL” zu. Hier werden sämtliche Berechtigungen gespeichert. Fällt diese Datenbank in fremde Hände, ist es für einen Neugierigen ein leichtes, mit der richtigen Kombination aus Host, Benutzerkennung und Passwort unbemerkt Daten auszuspionieren oder diese zu manipulieren. Siehe » Erster Eintrag in eine MySQL-Datenbank mit PDO (Abschnitt: Die Daten über ein Formular sicher eintragen).

🖝 Das maskieren von Sonderzeichen ist ganz wichtig als Schutz vor so genannten SQL-Injektionen. Bei einer SQL-Injektion versucht der Angreifer, eigene Datenbankbefehle einzuschleusen. Die Ziele dabei sind, Zugriff auf geschützte Bereiche zu erhalten, weitere Daten von anderen Kunden zu sehen oder einfach nur Schaden anzurichten.

🖝 Ein Angreifer, der mit einem Formular zum Einloggen konfrontiert wird, spekuliert über die Weise, wie die Abfrage zur Validierung des Benutzernamens und des Passwortes funktioniert. Ein Blick in den HTML-Quelltext gibt meist schon zu viel Preis. Besonders leicht hat es der Angreifer, wenn die gewählten Namen leicht zu erraten sind, etwa wenn der Benutzername in der Variable $benutzername und das Passwort in der Variable $passwort gespeichert werden und die zugehörigen Felder der DB-Tabelle genauso heißen.

Sicherheitslücke: Datei-. und Verzeichnisnamen

Viele Datei-. und Verzeichnisnamen laden zum „hacken” gerade zu ein: join, register, login, member, signup, recent, geheim, privat, … Verzichten Sie lieber auf solche und andere auffällige Namen.
» 10 Regeln zu Dateinamen

🖝 Der Inhalt der Seite, falls diese durch eine Suchmaschine indexiert wird, kann Text enthalten der nicht für eine Indexierung bestimmt ist. Abhilfe schafft hier » robots.txt (die Suchmaschinen müssen sich aber nicht unbedingt daran halten!) oder ein Verzicht auf bestimmte Schlagwörter.

Halten Sie Ihren Code unter Verschluss!

🖝 Wenn Sie „öffentlichen” Code verwenden (z.B. aus Skriptarchiven), gehen Sie das Risiko ein, dass systematisch nach diesem Code gesucht werden kann.

🖝 Wenn Sie Ihren eigenen Code veröffentlichen (z.B.: in Foren), gehen Sie das Risiko ein, dass potentielle Hacker darin gezielt auf die Suche nach Ihren kleinen Sünden gehen.

🖝 Wenn Sie öffentlichen Fremdcode verwenden wollen, kann sich die Umbenennung der Skripte bezahlt machen.

➤ Hier finden Sie keinen fertigen Code um Ihre Formulare zu schützen, dieser muss für jede Seite individuell angepasst werden.

Formular-Spam – Kostenlose Werbung

Hier weitere Tipps zu den oben genannten Möglichkeiten um Formular-Spam (Kommentar-Spam) zu vermeiden:

🖝 Enthält das Mitteilungsfeld sehr viel HTML-Code oder mehrere URLs, handelt es
sich meistens um Werbung  if (substr_count($_POST["eingabe"], "http:") > 3 ) { … 

🖝 Enthält das erste (in der Regel einzeilige) Formularfeld Zeilenumbrüche, deutet das auf einen Versuch von E-Mail Header Injection (de.wikipedia.org/wiki/Header-Injection) hin.
if (substr_count($_POST["email"], '\n') > 0 ) { …
if (substr_count($_POST["email"], '@') > 1 ) { …

🖝 Nach dem senden des HTML-Formulars stellen Sie die Informationen nochmals dem Benutzer zur Bestätigung zusammen (Vorschau). Erst Durch Betätigung mittels Formulars wird dann ein Mail-Versand ausgelöst.

🖝 Speichern Sie die Formulardaten (die Besucher machen) in einer Datei ab. Damit besteht die Möglichkeit, zu erkennen, wann Spamversuche statt gefunden haben. Bei „Spam” werten Sie die Datei aus und ergreifen Gegenmaßnahmen.

🖝 Verwenden Sie in Ihrem Forum oder Blog BBCode (Bulletin Board Code) statt HTML. Diese können anders als HTML-Tags keine Attribute wie zum Beispiel: <img src="bild.gif" onclick="location.href='example.com?virus';"> enthalten.
Mehr Infos zum BBCode auf » de.wikipedia.org/wiki/BB_Code

🖝 Prüfen Sie ob eine doppelte Eintragung durch falsche bzw. missbräuchliche Browserbenutzung (z.B.: „Aktualisieren/Reload”) möglich ist und treffen Sie dann entsprechende Vorkehrungen (zum Beispiel eine » Floodsperre) bei der Konstruktion der Datenverarbeitung.

🖝 Nach einem erfolgreichen Versand eines Formulars, sollte eine Weiterleitung über header("Location: …"); stattfinden. So kann der Benutzer die Daten über einem „Aktualisieren/Reload” (im Browser) das Formular nicht nochmals übermitteln.

Formulare – die Fehlerquelle schlechthin

Fehleingaben in Formularen sind immer möglich und wenn es sich nur um Schreibfehler des Benutzers handelt.

🖝 Vermeiden Sie Fehlerquellen, zum Beispiel: Eingabe eines bestimmten Datumsformats mit den <input>-Tag. Verwenden Sie dafür Auswahllisten, je eine für Tag, Monat und Jahr.

🖝 Aktuelle Browser bieten mehr Kontrolle zur Eingabe in den Formularen (required, pattern, … Siehe: » HTML- <input>-Element). Auch hier gilt es dann trotz Browser-Eingabewertprüfung die Angaben serverseitig mit PHP nochmals zu prüfen.

Tipps zu Formularen

🖝 Geben Sie beim testen absichtlich falsche Werte ein — bricht das Script mit einer Fehlermeldung ab oder kommt es zu irgendwelchen Fehlverhalten müssen Sie diese korrigieren.

🖝 Speichern Sie fehlgeschlagene Eingaben die durch die Eingangsprüfung des Skriptes durchgefallen sind in einem Logfile zusammen mit allen Daten, die Sie vom Verursacher haben (IP-Adresse, Browser etc.) ab, das hilft Ihnen dann mögliche Sicherheitslücken zu beheben.

🖝 Testen Sie Formulare gründlich auf Benutzbarkeit und Barrierefreiheit.
🖝 Oft sind Formularfelder zu klein um die Daten vernünftig einzugeben.
🖝 Formularfelder sollten nicht nebeneinander sondern untereinander stehen.
🖝 Bei Formulareingaben, welche Daten dauerhaft nicht wieder editierbar speichern, sollte immer eine Vorschau verfügbar sein.

🖝 Niemand füllt gerne Formulare aus.
Beschränken Sie die Angaben in den Formularen auf das nötigste (nur Pflichtfelder). Wenn Ihr Formular mehr Daten als unbedingt nötig vom Benutzer abfragt, dringen Sie zum einen zu stark in dessen Privatsphäre ein und machen ihm zum anderen den Vorgang Formular ausfüllen unnötigerweise unbequem. Beides sind Gründe für den Benutzer, das Formular nicht auszufüllen. Aus datenschutz-rechtlichen Gründen ist das Abfragen von Benutzerdaten, die man nicht unbedingt benötigt, sowieso recht heikel.

🖝 Formulare sollten sich nicht über viele Seiten erstrecken! Es gibt technische Gründe die es unmöglich machen alle Eingabefelder auf einer Webseite zu haben. Aber wenn es mehr als zwei Seiten auszufüllen gibt, so sollte man das dem Besucher von Anfang an klar machen, indem man z. B. angibt: „Schritt 1 von 3”.

🖝 Anmerkungen neben oder unter dem Eingabefeld, sind geeignet, beim Benutzer entstehende Fragen zu beantworten oder Unsicherheit abzubauen.

Schlusswort

Sicherheit ist ein fortlaufender Prozess, eine Schlacht und ein Kampf. Es ist Ihr Job als Entwickler, sich über die neuesten Sicherheitstrends auf dem laufenden zu halten und Ihre Anwendungen gründlich zu testen, bevor Sie diese ausliefern.

Oftmals genügt es, einige wenige Sicherheitsregeln konsequent umzusetzen, um die Anfälligkeit auf Attacken massiv einzudämmen.

Tipps

Zeitansage in JavaScript
Dieses JavaScript gibt die aktuelle Uhrzeit in Worten aus.
Mit JSON Daten zwischen JavaScript und PHP austauschen
JSON, ist ein kompaktes Datenformat in einer einfach lesbaren Textform zum Zweck des Datenaustauschs zwischen Anwendungen.
Suchanfrage an eine Datenbank über AJAX senden und empfangen
Ohne das die Seite neu geladen werden muss, kann man über JavaScript eine Suchanfrage an eine PHP-Datei senden (die dann eine DB-Tabelle ausliest) und die Ergebnisse auf der gleichen Seite ausgibt.
Visual Studio Code - Tipps
Mit den Tipps können Sie direkt einsteigen und lernen, wie Sie mit Visual Studio Code produktiv sein können.

Abonniere meinen RSS-Feed um über aktuelle Seiten benachrichtigt zu werden.