Dokumentation der Sicherheitsklasse (class.security.php)

Gesperrt
frederic.schneider_4fb
Beiträge: 967
Registriert: Do 15. Apr 2004, 17:12
Wohnort: Eschborn-Niederhöchstadt
Kontaktdaten:

Dokumentation der Sicherheitsklasse (class.security.php)

Beitrag von frederic.schneider_4fb »

Dokumentation der Sicherheitsklasse (class.security.php)
Stand: 4. September 2008
Autor: Frederic Schneider


Sicherheit in Webanwendungen: Warum eine Sicherheitsklasse?
Contenido ist ein komplexes und in den Jahren gereiftes System, das jedoch verschiedene, potentielle Angriffsziele kennt. Daher fiel die Entscheidung, eine globale Sicherheitsklasse zu entwerfen, die Methoden zur Verfügung stellt, die kritischen Punkte aus dem Weg zu räumen. Die Sicherheitsklasse geht dabei auf Cross-Site Scripting (XSS), Remote File Inclusion (RFI) und SQL-Injections ein.

Sicherheit durch ständige Präsenz in den Skripten
Durch manipuliertes Aufrufen durch Internetadressen von Contenido war es bislang bei bestimmten Serverkonfigurationen möglich, schädlichen Quelltext auszuführen und so für akute Sicherheitsprobleme zu sorgen. Diesen Gefahren wurde durch eine breite Kontrolle aller Variablen entgegen getreten. Außerdem wurde der Einzelaufruf von allen Dateien, die nicht eindeutige Einstiegsseiten sind, verhindert. Da jede der Hunderte Dateien einzeln auf etwaige Sicherheitslücken überprüft und ein Aufruf von Standardmethoden der Sicherheitsklasse eingebaut wurden, entstand so eine ständige Präsenz in den Skripten, sodass derartige Lücken der Vergangenheit angehören.

Manipulierung von Datenbanken gehören der Vergangenheit an
Ein großes, in Webanwendungen allgegenwärtiges Problem sind die so genannten SQL-Injections. Ebenfalls durch die Manipulierung von via Internetadressen übergebenen Variablen ist es unter gewissen Umständen möglich, Inhalte aus Datenbanken zu löschen oder etwa durch geschickte Datenbankabfragen Zugriff in die CMS-Verwaltung zu erhalten. Durch das "Escapen" werden solche Risiken grundsätzlich unterbunden.

Anwendung der Sicherheitsklasse
Um das manuelle Aufrufen von Einzelseiten, die keine Einstiegsseiten sind, zu verhindern, wird auf eindeutigen Einstiegsseiten eine Konstante namens "CMS_FRAMEWORK" mit dem Wert "true" gesetzt. Danach wird die Sicherheitsklasse inkludiert und mittels Contenido_Security::checkRequests(); Standard-Methoden aufgerufen.

In jeder Einzeldatei ist nun nur noch zu überprüfen, ob die Konstante gesetzt wurde. Dazu sind folgende drei Zeilen an den Anfang der jeweiligen Datei zu setzen:

Code: Alles auswählen

if(!defined('CON_FRAMEWORK')) {
	die('Illegal call');
}
Bei jeder Datenbankabfrage kommt zudem die Sicherheitsklasse in Einsatz. Dabei wird jede Variable mit der Funktion escapeDB() oder toInteger() "behandelt".

toInteger() findet ihren Einsatz, sobald die Variable eindeutig ein Integer, also eine Zahl ist.

Beispiel:

Code: Alles auswählen

$query = "SELECT * FROM con_art_lang WHERE idart = '" . Contenido_Security::toInteger($_GET['idart']) . "'";
Handelt es sich um keine Zahl, wird die Funktion escapeDB() eingesetzt, wobei ihr als zweiter Wert die initialisierte Datenbankklasse als Variable (i. d. R. $db, $db2 oder $db3) übergeben wird.

Beispiel:

Code: Alles auswählen

$db = new DB_Contenido;
$query = "SELECT * FROM con_art_lang WHERE title = '" . Contenido_Security::escapeDB($title, $db) . "'";
$db->query($query);
Gesetzt den Fall, es wurde keine Datenbank-Klasse initialisiert, kann statt $db auch "null" übergeben werden. Dies ist im Grundsatz aber nicht zu empfehlen.

Es ist bei escapeDB() vor allem darauf zu achten, dass eine Variable nicht zweimal mit escapeDB() "behandelt" wird. Dies könnte zu einem Fehlverhalten führen und passiert meist dann, wenn eine Datenbankabfrage in mehreren Schritten zusammen gebaut wird. Hier könnte die Variable einmal "behandelt" werden, wenn die Abfrage gebaut wird – und einmal die zusammengebaute Abfrage, wenn sie ausgeführt ist.

Die Sicherheitsklasse kennt im Übrigen folgende weitere Standard-Methoden:
  • checkSession() – überprüft, ob die übergebene Session-Variable dem Format entspricht; diese Überprüfung wird automatisch via des Aufrufes von checkRequests() in den Einstiegsseiten vorgenommen
  • isBoolean() – überprüft, ob die übergebende Variable ein Boolean-Typ ist und gibt im negativen Falle ein "false" zurück
  • isInteger() – überprüft, ob die übergebende Variable ein Integer-Typ, also eine Zahl ist und gibt im negativen Falle ein "false" zurück
  • isString() – überprüft, ob die übergebende Variable ein String-Typ, also ein Text ist und gibt im negativen Falle ein "false" zurück
  • toBoolean() – wandelt eine Variable in den Boolean-Typ um
  • toInteger() – wandelt eine Variable in den Integer-Typ, also in eine Zahl um
  • toString() – wandelt eine Variable in den String-Typ, also in einen Text um, wobei die Möglichkeit besteht, bestimmte HTML-Tags zu verbieten, indem nur die erlaubten angegeben sind; es ist daher als zweiten Wert ein "true" und als dritten die erlaubten Tags zu übergeben
Beispiel toString() mit erlaubten HTML-Tags:

Code: Alles auswählen

$string = Contenido_Security::toString($variable, true, '<strong><em><u>');
timo.trautmann_4fb
Beiträge: 472
Registriert: Di 15. Apr 2008, 15:57
Wohnort: Michelstadt
Kontaktdaten:

Beitrag von timo.trautmann_4fb »

Ergänzung neue Standard-Methoden:

filter($sString, $oDb) - filtert den String nach dem Muster der genericDB und escaped in anschließend mit der Funktion escapeDB() daher muss auch ein Datenbankobjekt übergeben werden. Zurück gegeben wird der bearbeitete String in der Squenz: escapeDB( htmlspecialchars( urlencode($sString))

unfilter($sString) - macht den Effekt der Filter Funktion rückgängig, in dem sie auf den String folgende verschachtelte Methoden anwendet und das Ergebnis zurück gibt: urldecode( htmldecode(unEscapeDB($sString))
unEscapeDB ist dabei die Funktion die den Effekt von escapeDB rückgänig macht und ebenfalls in der Klasse Security implementiert ist.
timo.trautmann_4fb
Beiträge: 472
Registriert: Di 15. Apr 2008, 15:57
Wohnort: Michelstadt
Kontaktdaten:

Beitrag von timo.trautmann_4fb »

Eigenständige Scripte, die extern aufrufbar sein sollten müssen dann mit diesen Zeilen beginnen, da es sonst zu einem illegal call kommen kann:

Code: Alles auswählen

if (!defined("CON_FRAMEWORK")) {
    define("CON_FRAMEWORK", true);
}

// include security class and check request variables
include_once ('./classes/class.security.php');
Contenido_Security::checkRequests();

include_once ('./includes/startup.php'); 
P.S. Je nach Speicherort des externen Scripts muss der Pfad zu class.security.php angepasst werden.
kummer
Beiträge: 2423
Registriert: Do 6. Mai 2004, 09:17
Wohnort: Bern, Schweiz
Kontaktdaten:

Beitrag von kummer »

vielleicht, wenn das an dieser stelle erlaubt ist, folgende anmerkung:

es ist durchaus nicht nötig, die gleiche variable bei jedem query über die security-klasse zu jagen (wie das zurzeit in vielen scripts der fall ist). wenn eine variable einmal validiert worden ist und keinen neuen wert zugewiesen erhalten hat oder wenn es aufgrund der ausführung des skriptes ausgeschlossen ist, dass sie einen anderen als den vorgesehenen wert aufweist, kann (und sollte man aus meiner sicht) sich und dem rechner es ersparen, die variablen immer und immer wieder zu prüfen.

werden die daten aus dem request bezogen, sind sie naturgemäss als nicht vertrauenswürdig einzustufen. gleiches gilt in eingeschränktem mass, wenn globale variablen innerhalb eines scriptes oder einer klasse verwendet werden. dabei reicht es allerdings völlig aus, die prüfung am anfang einmal vorzunehmen. von da an darf man sich darauf verlassen, dass sich deren wert nicht verändert hat, es sei denn, man macht es selber.

in bezug auf die verwendbarkeit von code ausserhalb von contenido ist vielleicht noch zu beachten, dass die security-klasse nur in contenido vernünftigerweise anwendbar ist. bei der erstellung von code (gilt insbesondere bei generischen klassen), die möglicherweise auch mal in einem anderen projekt verwendet werden, lohnt sich aus meiner sicht die validierung mit bordmitteln von php. insbesondere die möglichkeit des castings ist hier hier zu nennen sowie die methoden is_integer usw.

generell muss man sich überlegen, ob ein unverwarteter wert nicht eine ausnahmebehandlung erfordert, statt einer wert- und typenkonversion. wenn zum beispiel die globale $idart in einem modul plötzlich statt eines integers den typ string angenommen hat (mit entsprechenden inhalt), dann gibt es nur zwei mögliche szenarien: entweder hat ein zuvor ausgeführtes modul den wert überschrieben. dann soll mein modul aber eine entsprechende ausgabe machen und abbrechen, statt normal weiter auszuführen. weil dann liegt eine situation vor, die während der entwicklung des auftritts korrigiert werden muss. oder es handelt sich um einen - mindestens teilweise - erfolgreichen hackversuch. auch in diesem fall soll der code nicht ohne weiteres weiter ausgeführt werden.

bitte nicht als vorbehalt gegen die security-klasse verstehen. ich bin dafür. ungemein sogar. ;-)
aitsu.org :: schnell - flexibel - komfortabel :: Version 2.2.0 (since June 22, 2011) (jetzt mit dual license GPL/kommerziell)
blingbling
Beiträge: 12
Registriert: Do 15. Jan 2009, 14:19
Kontaktdaten:

Beitrag von blingbling »

Wo krieg ich diese Klasse her und wie baue ich sie ein?
timo.trautmann_4fb
Beiträge: 472
Registriert: Di 15. Apr 2008, 15:57
Wohnort: Michelstadt
Kontaktdaten:

Beitrag von timo.trautmann_4fb »

Hmm contenido/classes/class.security.php und ist schon eingebaut. Kann man eigentlich direkt verwenden ...
Gesperrt