Letzte Änderung: 17. Dezember 2022

PHP Security best practise


Nützliche Links

Link : ➞ PHP Webpage

Überprüfung auf Integer


if(!isset($_GET['id']) || !is_numeric($_GET['id'])) {
   die("Bitte eine ID spezifizieren");
}
$id = intval($_GET['id']);

if (!empty($_POST['number'])) {
	$number = $_POST['number'];
	$number = filter_var($number, FILTER_VALIDATE_INT);
	if ($number === false) {
		exit('Invalid Integer');
	}
}

if(is_int($_POST['mobile_number'])){
   return true; //// 0-9
} else {
   echo "Wrong number";
   return false;
}

Überprüfung auf Boolean


if (!empty($_POST['check'])) {
	$check = $_POST['check'];
	$check = filter_var($check, FILTER_VALIDATE_BOOLEAN);
}

Überprüfung das ein Feld ausgefüllt wurde


$username = isset($_POST['username']) ? $_POST['username'] : "";
 
if(empty(trim($username)) {
  die("Dein Benutzername darf nicht leer sein");
}

Überprüfung auf die Gültigkeit der E-Mail-Adresse


$email = isset($_POST['email']) ? $_POST['email'] : "";
 
if (empty($email) || !filter_var($email, FILTER_VALIDATE_EMAIL)) {
    die("Die Email-Adresse war ungültig");
}

Überprüfung auf die Gültigkeit einer URL


$url= isset($_POST['url']) ? $_POST['url'] : "";
 
if (empty($url) || !filter_var($url, FILTER_VALIDATE_URL)) {
    die("Die URL war ungültig");
}

Überprüfung der Länge der Eingabe


$passwort = isset($_POST['passwort']) ? $_POST['passwort'] : "";
 
if(strlen($passwort) < 8) {
  die("Dein Passwort muss mindestens 8 Zeichen haben");
}

Manipulierte GET-Abfragen & POST-Abfragen


Man sollte vermeiden bei GET-Abfragen sensible Aktionen (Logout, Bestellung von Ware, Löschung des Accounts etc.) durchzuführen. Nutzt dazu Formulare die per POST übertragen werden.

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
		// the request method is fine
} else {
	exit('Invalid Request');
}

if (isset($_POST['name'])){
   ...
}

$pageID = mysqli_real_escape_string($_POST['page_ID']);

$comment = htmlspecialchars(trim($_POST['comment']));

Schutz vor CSRF


Der Schutz gegen CSRF ist zum Glück relativ einfach. In eure Formulare und in eure Links die gewisse Aktionen auslösen (z.B. Logout-Link) müsst ihr eine geheime Information einbetten, die nur euer Server und der Browser des Benutzers kennt.

Beispielsweise generiert ihr nach dem Login einen zufälligen Wert und speichert diesen in einer Session ab:
	
//Nachdem sich der Benutzer eingeloggt hat
$_SESSION['csrf_token'] = uniqid('', true);

Jedes zu schützende Formular sowie jeder zu schützende Link wird nun dieser CSRF-Token übergeben. Aus dem Logout-Link wird entsprechend logout.php?csrf=$_SESSION['csrf_token'].

Ein zu schützendes Formular wird um ein hidden-Field erweitert, indem der Wert hinterlegt ist:
	
<input type="hidden" name="csrf" value="'.$_SESSION['csrf_token'].'">

Auf der Empfängerseite, also in eurem Logout-Script, in den Code-Stellen die eure Formulare etc. verarbeiten, könnt ihr überprüfen ob der übermittelte Wert dem abgespeicherten Wert in der Session entspricht:
	
//Bei GET-Aufrufen
if($_GET['csrf'] !== $_SESSION['csrf_token']) {
  die("Ungültiger Token");
}
 
//Bei Formularabfragen
if($_POST['csrf'] !== $_SESSION['csrf_token']) {
  die("Ungültiger Token");
}
 
//Weitere Aktionen, Logout, Änderung des Passworts etc.

Das Unterschieben von Links oder Formularen wird dadurch verhindert. Sofern ihr diesen Schutz also überall konsequent implementiert habt, ist eure Webanwendung recht sicher gegen Cross-Site-Request-Forgery.

Schutz vor Cross-Site-Scripting XSS


Zum Schutz sollten alle Benutzereingaben, wirklich alle Benutzereingaben, mittels htmlspecialchars() behandelt werden. htmlspecialchars() wandelt Sonderzeichen in entsprechende HTML-Codes um, so wird ein < durch &lt; ersetzt. Im Browser wird dieser HTML-Code so nicht mehr ausgeführt, sondern wie gewünscht dargestellt.

Es ist egal, ob ihr die Eingaben aus der Datenbank auslest, ihr GET-Parameter ausgebt oder alte Formulardaten, alle Daten sollten mittels htmlspecialchars() entsprechend umgewandelt werden. Um die Arbeit etwas zu vereinfachen, bietet es sich an kürzere Schreibweise für das behandeln von Nutzerdaten zu definieren, beispielsweise die Funktion e() für escape:

function e($string) {
  return htmlspecialchars($string, ENT_QUOTES, 'UTF-8');
}

if (!empty($_POST['username']) && !empty($_POST['email'])) {
	$username = trim(htmlspecialchars($_POST['username']));
	$email = trim(htmlspecialchars($_POST['email']));
}

Creating Your Own Class To Validate Inputs


class  Input {
	static $errors = true;

	static function check($arr, $on = false) {
		if ($on === false) {
			$on = $_REQUEST;
		}
		foreach ($arr as $value) {	
			if (empty($on[$value])) {
				self::throwError('Data is missing', 900);
			}
		}
	}

	static function int($val) {
		$val = filter_var($val, FILTER_VALIDATE_INT);
		if ($val === false) {
			self::throwError('Invalid Integer', 901);
		}
		return $val;
	}

	static function str($val) {
		if (!is_string($val)) {
			self::throwError('Invalid String', 902);
		}
		$val = trim(htmlspecialchars($val));
		return $val;
	}

	static function bool($val) {
		$val = filter_var($val, FILTER_VALIDATE_BOOLEAN);
		return $val;
	}

	static function email($val) {
		$val = filter_var($val, FILTER_VALIDATE_EMAIL);
		if ($val === false) {
			self::throwError('Invalid Email', 903);
		}
		return $val;
	}

	static function url($val) {
		$val = filter_var($val, FILTER_VALIDATE_URL);
		if ($val === false) {
			self::throwError('Invalid URL', 904);
		}
		return $val;
	}

	static function throwError($error = 'Error In Processing', $errorCode = 0) {
		if (self::$errors === true) {
			throw new Exception($error, $errorCode);
		}
	}
}

// validate an integer
$number = Input::int($_POST['number']);

// validate a string
$name = Input::str($_POST['name']);

// convert to boolean
$bool = Input::bool($_POST['boolean']);

// validate an email
$email = Input::email($_POST['email']);

// validate a URL
$url = Input::url($_POST['url']);