{{NEWPAGE>test}} ====== Systemsicherheit ====== (ein ganzes Paket an Einzelelementen. Von Passwortverschlüsselung bis zum Schutz vor CrossSiteScripting.) ===== CsfrTokens ===== Ein wesentlicher Bestandteil zum Schutz gegen CrossSiteScripting ist der Einsatz von Tokens bei der Übermittlung von Formularen und sonstigen Änderungsanforderungen. WebsiteBaker stellt dafür die Klasse **bin\Security\CsfrTokens** zur Verfügung. Diese Klasse wird grundsätzlich immer automatisch vom Kern geladen und stellt ihre Methoden zur Verfügung. Die Konfiguration der Klasse und auch der Einsatz der Methoden wurde so einfach wie möglich gehalten. ==== Begriffserklärung ==== **//TOKEN//** => Ehemals **FTAN**. Dieser Begriff wurde in Anlehnung an die **T**rans**A**ktions**N**ummern beim Onlinebanking gewählt, da auch sie nur für eine einmalige Transaktion innerhalb eines festgelegten Zeitraums gültig sind.\\ Im Unterschied zu der einfachen, 4-stelligen TAN jedoch besteht ein vollständiger Token aus einem 6-stelligen, alphanumerischen Bezeichner sowie dem zugehörigen, ebenfalls 6-stelligen, alphanumerischen Wert. Sowohl Bezeichner als auch der Wert ändern sich bei jedem normalen Request auf Zufallsbasis. Bei Ajaxaufrufen ändert sich nur der Value-Anteil des Tokens. **//IDKEY//** => Ist das zweite Standbein der Sicherung. Er wird hauptsächlich eingesetzt, um die Datensatz-IDs in Formularen und anderen Requests zu verschleiern. Die ID wird dabei durch einen einmaligen, 6-stelligen, alphanumerischen Wert ersetzt. Wird ein gleicher Wert mehrmals verschlüsselt, so bekommt er **immer** einen anderen Ersatzwert. Für jeden Request, für jedes Formular können beliebig viele IDKEYs erzeugt werden. Der IDKEY verhindert z.B. zuverlässig, dass auf Clientseite in einem Änderungsformular die reale DatensatzId vor dem Absenden manipuliert werden kann und dadurch unzulässigerweise ein falscher Datensatz geändert oder gar gelöscht wird. ==== Feste Einstellungen ==== ^ Konstante ^ Wert ^ Beschreibung ^ ^ LIFETIME_MIN | 900 | Minimale Lebensdauer eines Tokens in Sekunden | ^ LIFETIME_MAX | 5400 | Maximale Lebensdauer eines Tokens in Sekunden | ^ LIFETIME_STEP | 900 | Einstellbare Schrittweite zwischen MIN und MAX in Sekunden | ^ DEBUG_LIFETIME | 180 | Tokenlebensdauer in Sekunden im DEBUG-Modus | Die maximale Lebenszeit von Tokens ist auf eine vernünftige, sinnvolle Bearbeitungsdauer eingestellt und sollte auf keinen Fall verlängert werden. Grundsätzlich verfallen auch alle Tokens, wenn die aktuelle Session ihren Timeout erreicht.\\
**Je länger die mögliche Bearbeitungszeit wird,\\ desto grösser wird das Risiko einer erfolgreichen Attacke.**
---- ==== Registry-Settings ==== //(Variable Einstellmöglichkeiten)//\\ Diese vier Werte können im ACP unter //Settings-Sicherheit// eingestellt werden. **SecTokenLifeTime**\\ Die 'Lebensdauer' von Tokens kann in Schritten von 15 Minuten zwischen 15 Minuten und 1,5 Stunden eingestellt werden.\\ Wird ein negativer Wert (<0) eingegeben, so wird der Debug-Modus mit einer Lebensdauer von 3 Minuten aktiviert. **SecTokenFingerprint**\\ Hiermit kann das Fingerprinting des Client eingeschaltet(**true**) oder ausgeschaltet(**false**) werden.\\ Die Abschaltung wird aus Sicherheitsgründen **nicht** empfohlen! **SecTokenIpv4Netmask**\\ Hiermit wird der zu überprüfende Netzanteil einer IPv4 Adresse festgelegt. Möglich sind Netzmaskenlängen von 1-32 Bit. Eine Länge von 0 Bit setzt die IPv4-Überprüfung außer Funktion. Je höher der angegebene Wert ist, desto restriktiver ist die Einstellung. **SecTokenIpv6Netmask**\\ Hiermit wird der zu überprüfende Präfix einer IPv6 Adresse festgelegt. Möglich sind Längen von 1-128 Bit. Eine Länge von 0 Bit setzt die IPv6-Überprüfung außer Funktion. Je höher der angegebene Wert ist, desto restriktiver ist die Einstellung. ---- ==== Verfügbare Methoden ==== === ::getToken === **Prototype:** getToken(void):array\\ Gibt ein Array zurück, das die FTAN des aktuellen Requests sowie zusätzliche Daten zurückgibt. Während des Programmstarts wird automatisch ein neuer Token erzeugt, der dann während des laufenden Requests beliebig oft abgerufen werden kann. Gibt ein Array mit folgenden Schlüsseln zurück: ^Schlüssel ^ Value-Type ^ Beschreibung ^ | name | string | Bezeichner des Tokens | | value | string | Wert des Tokens | | remain | int | Sekunden bis zum Timeout | | previous | string | vorheriger Wert des Tokens | Der Wert 'remain' kann zur Anzeige eines Timeout-Countdowns mittels Javascript genutzt werden. === ::checkToken === **Prototype:** checkTokenn(void):bool\\ Es wird überprüft, ob im aktuellen Request ein gültiger Token übergeben wurde. Die Methode sucht die nötigen Angaben automatisch in den Argumenten des aktuellen Requests. Diese Methode merkt sich das Ergebnis der Prüfung, welches während eines Requests beliebig oft abgefragt werden kann. Bei gültigem Token ist der Rückgabewert TRUE andernfalls FALSE. === ::createIdKey === **Prototype:** createIdKey(scalar $mValue):string\\ Der an die Methode übergebene Wert wird gesichert und dafür ein einmaliger, 6-stelliger, alphanumerischer Schlüsselwert zurückgegeben. Es können alle skalaren Datentypen übergeben werden: **//String//**, **//Integer//**, **//Float//**. Der zurückgegebene Schlüsselwert wird einfach anstatt des Originalwertes an den Client gesendet. === ::isValidIdKey === **Prototype:** isValidIdKey(string $sToken[, bool $bPreserve = false]):bool\\ * **//$sToken//** Ein String wird überprüft, ob er einen gültigen IdKey darstellt. Die Rückgabe ist schlicht 'true' oder 'false'. Diese Methode kann beliebig oft angewendet werden. === ::decodeIdKey === **Prototype:** decodeIdKey(string $sToken[, bool $bPreserve = false]):scalar\\ * **//$sToken//** Ein Token, bzw. IdKey, dessen realer Wert ausgelesen werden soll. Dieser Wert kann nur ein einziges MAL gelesen werden. === ::sanitizeTokenLifeTime === **Prototype:** integer sanitizeTokenLifeTime(integer $iLifeTime)\\ Ein übergebener Integer-Wert wird auf eine verfügbare Intervallstufe zwischen LIFETIME_MIN und LIFETIME_MAX korrigiert. Ein negativer Wert bei aktiviertem DEBUG-Modus auf DEBUG_LIFETIME, ansonsten auf LIFETIME_MIN. Ein ungültiger Wert grundsätzlich auf LIFETIME_MIN. Der berechnete Wert wird zurückgegeben. === ::getTokenLifeTime === **Prototype:** array getTokenLifeTime(void)\\ Gibt ein Array mit folgenden Schlüsseln zurück: ^Schlüssel ^ Beschreibung ^ | min | minimal einstellbare Lebensdauer in Sekunden | | max | maximal einstellbare Lebensdauer in Sekunden | | step | Schrittweite in Sekunden | | value| Eingestellte Laufzeit in Sekunden | Wozu werden diese Werte benötigt? Das ACP um Beispiel holt sich diese Angaben, um die Einstellung komfortabel verändern zu können. ---- ==== Anwendungsbeispiele ==== :!: **Achtung:** Requests müssen eindeutig sein! Der 'action' Parameter eines **//form//** Tags mit Method="POST" darf keine zusätzlichen URL-Argumente ( //*.php?x=1// ) enthalten. Eventuell notwendige Zusatzargumente müssen mit //// übergeben werden. === Formular === use bin\Security\CsfrTokens; $aToken = CsfrTokens::getToken(); $sOutput = '
' . '' . ''; echo $sOutput; // Auswertung if (CsfrTokens::checkToken()) { /* alles OK */ $iRecordId = CsfrTokens::decodeIdKey('record_id'); […] } === Link === use bin\Security\CsfrTokens; $aToken = CsfrTokens::getToken(); $sOutput = 'Tu was'; echo $sOutput; // Auswertung if (CsfrTokens::checkToken()) { /* alles OK */ $iRecordId = CsfrTokens::decodeIdKey('record_id'); […] } === Twig-Template === use bin\Security\CsfrTokens; /* view-script */ $aTwigdata['TargetUrl'] = 'index.php'; $aTwigdata['TOKEN'] = CsfrTokens::getToken(); $aTwigdata['RecordId'] = CsfrTokens::createIdkey($record_id); twig-template // Beispiel 1 […] // Beispiel 2 Tu was
/* save-script */ // Beispiel 1 + 2 use bin\Security\CsfrTokens; if (CsfrTokens::checkToken()) { $record_id = CsfrTokens::decodeIdKey('record_id'); […] } ==== Einsatz mit AJAX ==== CsfrTokens in Verbindung mit Ajax erfordert etwas mehr Aufmerksamkeit. Wobei es Unterschiede zwischen den Major-Versionen von WebsiteBaker gibt.
Die folgende Beschreibung gilt vorerst nur für Versionen der 2er Serie, deren Module noch mit der veralteten Technik arbeiten und PHP-Dateien im Modulverzeichnis direkt aufrufen.
Grundsätzlich gilt natürlich auch für Ajax-Requests die übliche Regel, dass Änderungsanfragen einen gültigen TOKEN mitliefern müssen. Prinzipiell ist das bei normalen Requests ja kein Problem, da als Antwort immer eine komplett neue Seite aufgebaut wird die automatisch auch neue, gültige TOKENSs etc. enthält.\\ Bei einem Ajax-Request hingegen wird die Seite ja **nicht** automatisch neu aufgebaut. Also werden auch für die verbrauchten keine neuen TOKENs eingetragen. Jeder weitere Aufruf würde also deshalb zwingend eine Fehlermeldung zur Folge haben.\\ Im Rückschluss bedeutet das, dass in der Ajax-Antwort ein neuer TOKEN mit zurückgeliefert werden muss, die die bisherige ersetzt.\\ Ab der Version 1.0.1 stellt CsfrTokens die TOKEN-Unterstützung von AJAX-Requests bereit.\\ Um diese neue Funktionalität nutzen zu können, müssen 4 Bedingungen erfüllt werden.
- Ein AJAX-Request muss selbstverständlich die beiden Teile des TOKEN (name, value) senden. - Ein AJAX-Request muss den HTTP-Header **KIPA-XAJAX: 1** senden. - Ein AJAX-Response muss vom Server ein **TOKEN** Objekt zurück bringen. - Browserseitig muss ein Script dafür sorgen, dass das zurückgelieferte **Token** Objekt verarbeitet wird (//RenewToken(oToken)//).
**zu Punkt (1):**\\ Bei GET Requests genügt ein einfacher URL-Argumentestring mit den TOKEN-Werten url?foo=xx&abcdef=123456 angehängt.\\ Für POST wird einfach ein zusätzliches Inputfeld verwendet. **zu Punkt (2):**\\ Vor dem Senden der Daten den **//KIPA_XAJAX//** HTTP-Header senden. XHR.setRequestHeader('KIPA-XAJAX', '1');\\ WebsiteBaker benötigt diesen Header, um einen AJAX-Request sicher zu detektieren. **zu Punkt (3):**\\ die Rückgabe des Token-Objektes. Das ist durch einen Einzeiler sehr einfach zu erledigen.\\ echo json_encode(\bin\Security\CsfrTokens::getToken()); Selbstverständlich kann dieser Einzeiler auch in jede komplexere Rückgaberoutine eingebaut werden.\\ **zu Punkt (4):**\\ Das ist der 'aufwändigste' Punkt. Das zurückgegebene TOKEN Objekt muss an z.B. die Funktion RenewToken() übergeben werden. Diese Funktion tauscht sämtliche alten TOKENs im gesamten Dokument gegen die neu erhaltenen aus. Zusätzlich kann noch eine Funktion übergeben werden, die eine SessionProgressBar neu startet: RenewTokenFtan(oToken, callBackFunction); IDKEYs werden durch Ajax-Requests **nicht** verändert oder ungültig. ==== Timeout Progressbar ==== Dies ist eine von sehr vielen Möglichkeiten, eine Progressbar einzubauen, die die Restzeit bis zum Ablauf der Session/des Tokens anzeigt. Es ist nur ein Beispiel, wie derartiges funktionieren könnte. Selbstverständlich kann jeder seine persönliche Lösung des Problems erstellen! /* css */
 
{{ Lang.SESSION_TIMEOUT }}!!|{{ Lang.REMAINING_TIME }}  
/* javascript */