Sicherheit:
Eingaben Prüfen
Durch Eingabe von Code in die Adresszeile (in den Querrystring) oder in ein Formularfeld, welches direkt zu einer Abfrage führt oder zu einer Ausgabe im Browser oder welches einem Datenbankeintrag / einer Datenbankabfrage dient, lässt sich böser Code einschmuggeln und ausführen. Es darf keiner übermittelten Variablen vertraut werden, auch nicht solchen aus 'hidden-fields'. Ich kann diese bösen Strings mit folgenden Mitteln entschärfen.
Wichtige Stichworte zum Thema Sicherheit sind:
>> Cross-Side Scripting
und >> SQL-Injection!
Allgemeine Sicherheitsregeln:
- Alle Variablen im Vornherein initialisieren, um sie überprüfen zu können
- Wisse woher die Variablen kommen: am besten $_POST verwenden (statt $_GET oder gar $_REQUEST)
- Validiere den Input durch Funktionen
- Zähle und vergleiche oder limitiere die zu erwartende Anzahl Worte oder Zeichen.
- Kontrolliere nicht nur auf böse Charakter, sondern kontrolliere, ob der übermittelte Wert dem erwarteten Wert entspricht, z.B. durch die Regulären Ausdrücke.
- Fehlermeldungen im produktiven system ganz abschalten: error_reporting(0);
PHP Code
Umwandeln von Benutzereingaben
-
strip_tags()
strip_tags() - löscht alle HTML und PHP Tags -
htmlspecialchars()
htmlspecialchars($var,ENT_QUOTES) - Konvertiert die HTML Spezialcharakter < in <, > in >, & in & und " in " um. Mit dem zweiten Parameter ENT_QUOTES auch noch ' in '.
quote_style gibt zusätzlich das Verfahren gegenüber Anführungszeichen an:
ENT_COMPAT konvertiert nur doppelte Anführungszeichen und lässt einfache Anführungszeichen unverändert (Grundeinstellung wenn nichts.
ENT_QUOTES konvertiert sowohl doppelte als auch einfache Anführungszeichen.
ENT_NOQUOTES lässt doppelte und einfache Anführungszeichen unverändert.
htmlspecialchars_decode() wandelt alles wieder zurück. -
htmlentities()
htmlentities(string, quote_style) - Wandelt zusäzlich auch die Umlaute ü, ö und ä um.
html_entity_decode() wandelt alles wieder zurück. -
addslashes()
addslashes(), quotemeta() oder addcslashes(), setzen einen Backslash vor Anführungszeichen (einfache und doppelte)
stripslashes() löscht die backslashes, die eine aktivierte magic_quotes Einstellung beim Übertragen von Formulardaten erzeugt hat. -
preg_replace()
preg_replace($suchen,$ersetzen,$imstring) ersetzt in Strings und Arrays reguläre Ausdrücke.
Auf diesen String angewendet erzeugen obige Funktionen folgenden Output:
$myInput="<b>Ich bin fett</b> und ich hab 'n Apostrophe ähhh und \"ich bin angeführt\"."
Ich bin fett und ich hab 'n Apostrophe ähhh und "ich bin angeführt".
htmlspecialchars:
<b>Ich bin fett</b> und ich hab 'n Apostrophe ähhh und "ich bin angeführt".
htmlspecialchars mit ENT_QUOTES:
<b>Ich bin fett</b> und ich hab 'n Apostrophe ähhh und "ich bin angeführt".
htmlentities mit ENT_QUOTES:
<b>Ich bin fett</b> und ich hab 'n Apostrophe ähhh und "ich bin angeführt".
addslashes:
<b>Ich bin fett</b> und ich hab \'n Apostrophe ähhh und \"ich bin angeführt\".
preg_replace('/(<|>|&|'|")/','*',$myInput):
*b*Ich bin fett*/b* und ich hab *n Apostrophe ähhh und *ich bin angeführt*.
Typen erkennen von Zahlen / umwandeln in Zahlen
-
is_string()
is_string(), ist der Input ein String? (stimmt gibt 1/TRUE zurück wenn's stimmt, sonst 0/FALSE - was nichts ist) -
is_numeric()
is_numeric(), ist der Input ein numerischer String? (stimmt gibt 1 zurück ...) -
is_int()
is_int(), ist der Input eine Zahl? (stimmt gibt 1 zurück ...) -
ctype_digit()
ctype_digit(), prüft einen String auf Ziffern und anerkennt vorangestellte Nullen als solche. (stimmt gibt 1 zurück ...) -
(int)$benutzereingabe; oder intval($benutzereingabe);
mit (int)$benutzereingabe; oder auch mit intval($benutzereingabe); erfolgt Umwandlung in integer. (Erfolg gibt die gewandelte Zahl zurück!) -
settype($Variable, Typ);
Mit settype($Variable, int); erfolgt Umwandlung in integer. (Erfolg gibt 1 zurück!)
Auf diese Strings angewendet erzeugen obige Funktionen folgenden Output:
007666
007is666
1
1
is_numeric:
1
is_int:
ctype_digit:
1
intval:
7666
7
settype int:
1
1
Verschlüsselung
Die Umwandlungen durch folgende Funktionen können genutzt werden um eindeutige Sessions zu generieren.
md5()
md5($myInput): f206f194e4dc19cca1429f307d88abf1
crc32()
crc32($myInput): 780040031
Verstecken und Verbieten
.htaccess
Zugangsdaten (z.B. in .inc Dateien abgelegt), sollen nicht in ungeschützten Verzeichnissen liegen! Errät man die Namen, kann die Datei einfach im Browser aufgerufen werden. Durch .htaccess-Dateien in speziel benannten Ordnern, kann der Zugriff auf diese Dateien von Aussen her verboten werden, der Zugriff von innen her (für die Scripte) bleibt dabei erhalten.
<FilesMatch "\.inc$"> Deny from all </FilesMatch>
Zugriff auf mehrere Datei-Typen verbieten:
<FilesMatch "\.(inc|dat)$"> Deny from all </FilesMatch>
Verstecken oder Zugriffverweigerung wäre eigentlich unnötig, würden die Include-Dateien etwa so heissen: inc_wasichmach.php (statt Endung .inc), den PHP-Dateien werden geparst und somit leer dargestellt. Mehr zu .ht-Dateien (im Teil 'Andere' im Kapitel 'Apache Server'). Mehr zu Passwortschutz durch .htaccess (im Teil 'Andere' im Kapitel 'Apache Server').
Achtung, die Angabe der zu schützenden Dateien in der Datei robots.txt (bitte nicht indexieren) ist natürlich ein Humbug!
Siehe: Server
SQL Code
- Stelle nie als Superuser oder Owner einer Datenbank eine Verbindung zur Datenbank her.
Verwende immer speziell angelegte Benutzer mit sehr limitierten Rechten! - Protokolliere die Vorgänge, welche zu einer Veränderung der Datenbank führen
- Mache Backups deiner DB z.B. mit 'MySQLDumper' Freeware (http://mysqldumper.de/)
- Nutze Funktionen (vor Einträgen in Datenbanken): mysql_real_escape_string() / >> mysql_real_escape_string()
- Verhindere gezielt das Löschen ganzer Tabellen oder mehrer Datensätze. Suche in Usereingaben (Querrystring, GET, POST, REQUEST) nach Injections wie
; DROP TABLE tabellenname;--', die beiden Bindestriche sorgen dafür, dass das ' als Kommentar ignoriert wird, so wird durch den angehängten Befehl nicht einmal eine Fehlermeldung erzeugt.
<?php
// Anstatt
$abfrage = "SELECT spalte1 FROM tabelle WHERE spalte2 = '".$_POST['spalte2Wert']."'";
$query = mysql_query($abfrage) or die("Datenbankabfrage ist fehlgeschlagen!");
mysql_real_escape_string
// sollte Folgendes verwendet werden:
$abfrage = "SELECT spalte1 FROM tabelle WHERE spalte2 = '".mysql_real_escape_string($_POST['spalte2Wert'])."'"; $query = mysql_query($abfrage) or exit;
?>
HTML/JavaScript Code
<?php
$boesercode = "<script>alert('XSS');</script>";
echo "Sie haben ".htmlentities($boesercode,ENT_QUOTES)." eingegeben";
//Ausgabe: Sie haben <script>alert('XSS');</script> eingegeben
?>