Schützen Sie eine CodeIgniter-Anwendung vor CSRF

Im heutigen Lernprogramm erfahren Sie, wie Sie Ihre CodeIgniter-Anwendung (vor 2.0) vor Angriffen durch Cross-Site Request Forgery schmerzlos schützen können. Die Bibliothek, die wir heute erstellen, wird alle Schutzmechanismen automatisieren und Ihre Website stärker und sicherer machen.


Schritt 1 - Den Angriffsvektor verstehen

Cross-Site Request Forgery-Angriffe basieren auf ungeschützten Formularen auf Ihren Sites.

Ein Angreifer kann auf seiner Website ein gefälschtes Formular erstellen, beispielsweise ein Suchformular. Dieses Formular kann Eingaben verbergen, die schädliche Daten enthalten. Jetzt wird das Formular nicht wirklich an die Site des Angreifers gesendet, um die Suche durchzuführen. In Wirklichkeit weist das Formular auf Ihre Seite? ˅! Da Ihre Website darauf vertrauen kann, dass das Formular echt ist, durchläuft es die angeforderten (und möglicherweise böswilligen) Aktionen.

Stellen Sie sich vor, ein Benutzer ist bei Ihrer Site angemeldet und wird aus irgendeinem Grund zur Site des Angreifers umgeleitet (Phishing, XSS, Sie nennen es). Das Formular des Angreifers kann auf das Löschformular Ihres Kontos auf Ihrer Website verweisen. Wenn der Benutzer eine "Suche" auf der Angreifer-Site durchführt, wird sein Konto ohne Wissen des Benutzers gelöscht!

Es gibt zahlreiche Möglichkeiten, diese Art von Angriffen zu verhindern.

  • Überprüfen Sie den HTTP Referer-Header und sehen Sie nach, ob er zu Ihrer Site gehört. Das Problem bei dieser Methode ist, dass nicht alle Browser diesen Header übermitteln (ich hatte dieses Problem einmal mit IE7); es könnte trotzdem geschmiedet werden.
  • Eine andere Methode (die wir verwenden werden) besteht darin, eine zufällige Zeichenfolge (ein "Token") in jedes Formular einzufügen und dieses Token in der Benutzersitzung zu speichern. Auf jeder POST anfordern, vergleichen Sie das übergebene Token mit dem im Geschäft, und, wenn sie sich unterscheiden, verweigern Sie die Anforderung. Ihre Site muss jedoch noch vor XSS geschützt werden, da diese Methode sonst unbrauchbar wird.

Schritt 2 - Planung

Wir müssen für jede Anfrage drei Dinge tun:

  • Wenn die Anfrage a ist POST anfordern, bestätigen Sie, dass das übergebene Token.
  • Generieren Sie ein Token, falls es keinen gibt.
  • Injizieren Sie das Token in alle Formen. Dies macht die Methode nahtlos und problemlos, da keine Änderungen an Ihren Ansichten erforderlich sind.

Um dies automatisch durchzuführen, verwenden wir CodeIgniter-Hooks. Hooks ermöglichen es uns, alle Aktionen für verschiedene Teile der Anfrage auszuführen. Wir brauchen drei:

  • post_controller_constructor - Um das gesendete Token zu überprüfen, benötigen wir eine post_controller_constructor Haken. Wenn Sie diese Aktion vor diesem Ereignis aktivieren, erhalten Sie keinen korrekten Zugriff auf die Instanz von CodeIgniter.
  • Generieren Sie das Token - Um das Token zu generieren, verwenden wir denselben Hook wie zuvor. Dies ermöglicht uns den Zugriff darauf, falls wir es manuell in unseren Ansichten drucken müssen.
  • display_override - Um das Token automatisch in unsere Ansichten einzufügen, müssen wir das verwenden display_override Haken. Dies ist jedoch ein kniffliger Haken, da er, wie der Name schon sagt, die Anzeige der Ansichten überschreibt. Wenn Sie diesen Hook verwenden, müssen Sie den Inhalt selbst ausgeben (weitere Informationen finden Sie in der CodeIgniter-Dokumentation)..

Schritt 3 - Token-Generierung

Lass uns anfangen. Wir gehen Schritt für Schritt vor, um alles so gründlich wie möglich zu erklären. Wir erstellen die Methode, die das Token zuerst generiert, sodass wir anschließend alles richtig testen können. Erstellen Sie eine Datei in Ihrem System / Anwendung / Haken Ordner mit dem Namen "csrf.php"und fügen Sie den folgenden Code ein:

CI = & get_instance (); 

Hoffentlich sollte das, was wir oben hinzugefügt haben, für Sie eher einfach erscheinen. Wir erstellen eine Klasse, genannt CSRF-Schutz, eine Instanzvariable für die CodeIgniter-Instanz, zwei statische Variablen für den Namen des Parameters, in dem das Token gespeichert wird, und eine, um das Token selbst zu speichern, um den Zugriff auf die gesamte Klasse zu ermöglichen. Innerhalb des Klassenkonstruktors (__konstruieren) rufen wir einfach die CodeIgniter-Instanz ab und speichern sie in unserer entsprechenden Instanzvariablen.

Hinweis: Der "Name des Parameters" ist der Name des Felds, das das Token enthält. In den Formularen ist dies der Name der versteckten Eingabe.

Fügen Sie nach dem Klassenkonstruktor den folgenden Code ein:

/ ** * Erzeugt ein CSRF-Token und speichert es in einer Sitzung. Es wird nur ein Token pro Sitzung generiert. * Dies muss an einen Post-Controller-Hook gebunden sein und vor dem Hook *, der die inject_tokens-Methode () aufruft. * * @return void * @author Ian Murray * / public function generate_token () // Sitzungsbibliothek laden, falls nicht geladen $ this-> CI-> load-> library ('session'); if ($ this-> CI-> session-> userdata (self :: $ token_name) === FALSE) // Generieren Sie ein Token und speichern Sie es in einer Sitzung, da der alte abgelaufen zu sein scheint. self :: $ token = md5 (uniqid (). microtime (). rand ()); $ this-> CI-> session-> set_userdata (self :: $ token_name, self :: $ token);  else // Setzt sie auf lokale Variable, um den einfachen Zugriff zu ermöglichen self :: $ token = $ this-> CI-> session-> userdata (self :: $ token_name); 

Schritt für Schritt:

  • Wir laden die Sitzungsbibliothek, falls sie nicht automatisch geladen wird. Wir benötigen dies, um das Token zu speichern.
  • Wir ermitteln, ob das Token bereits generiert wurde. Wenn die Benutzerdaten Methode kehrt zurück FALSCH, dann ist der token noch nicht vorhanden.
  • Wir generieren ein Token und speichern es in der Klassenvariablen, um den Zugriff zu erleichtern. Das Token könnte eigentlich fast alles sein. Ich habe diese drei Funktionen verwendet, um sicherzustellen, dass dies der Fall ist sehr zufällig.
  • Wir speichern es dann in der Sitzungsvariablen mit dem zuvor konfigurierten Namen.
  • Wenn der Token bereits vorhanden war, haben wir nicht generieren Sie es und speichern Sie es stattdessen in der Klassenvariablen, um den Zugriff zu erleichtern.

Schritt 4 - Tokenvalidierung

Wir müssen sicherstellen, dass das Token übermittelt wurde und gültig ist, falls es sich um eine Anfrage handelt POST anfordern. Fahren Sie fort und fügen Sie den folgenden Code in Ihr ein csrf.php Datei:

/ ** * Überprüft ein übermitteltes Token, wenn eine POST-Anforderung erfolgt. * * @return void * @author Ian Murray * / public function validate_tokens () // Ist dies eine Postanforderung? if ($ _SERVER ['REQUEST_METHOD'] == 'POST') // Ist das Tokenfeld gesetzt und gültig? $ posted_token = $ this-> CI-> input-> post (self :: $ token_name); if ($ posted_token === FALSE || $ posted_token! = $ this-> CI-> session-> userdata (self :: $ token_name)) // Ungültige Anforderung, Fehler 400 senden. show_error ('Anforderung war ungültig. Token stimmten nicht überein. ', 400); 
  • Oben bestätigen wir die Anfrage aber nur wenn es ein ist POST Antrag, was bedeutet, dass tatsächlich ein Formular übermittelt wurde. Wir prüfen das, indem wir uns die ansehen REQUEST_METHOD innerhalb des $ _SERVER super global.
  • Prüfen Sie, ob das Token tatsächlich gebucht wurde. Wenn die Ausgabe von $ this-> CI-> input-> post (self :: $ token_name) ist FALSCH, dann wurde der token nie gebucht.
  • Wenn das Token nicht veröffentlicht wurde oder nicht mit dem von uns generierten übereinstimmt, lehnen Sie die Anforderung mit dem Fehler "Bad Request" ab.

Schritt 5 - Injizieren Sie Token in die Ansichten

Das ist der lustige Teil! Wir müssen die Jetons in allen Formen injizieren. Um uns das Leben leichter zu machen, werden wir zwei Meta-Tags in unsere einfügen (Schienenähnlich). Auf diese Weise können wir das Token auch in AJAX-Anforderungen aufnehmen.

Hängen Sie den folgenden Code an Ihre csrf.php Datei:

/ ** * Dadurch werden in alle POST-Formulare mit dem csrf-Token ausgeblendete Tags eingefügt. * Spritzt auch Meta-Header ein  der Ausgabe (falls vorhanden) für den einfachen Zugriff * von JS-Frameworks. * * @return void * @author Ian Murray * / public function inject_tokens () $ output = $ this-> CI-> output-> get_output (); // In Form injizieren $ output = preg_replace ('/ (<(form|FORM)[^>] * (method | METHOD) = "(post | POST)" [^>] *>) / ',' $ 0', $ output); // Injizieren in  $ output = preg_replace ('/ (<\/head>) / ',''. "\ n". ''. "\ n". '$ 0', $ Ausgabe); $ this-> CI-> output -> _ display ($ output); 
  • Da das ein ist display_override Hook, müssen wir die generierte Ausgabe von CodeIgniter abrufen. Wir machen dies mit der $ this-> CI-> output-> get_output () Methode.
  • Um die Tags in unsere Formulare einzufügen, verwenden wir reguläre Ausdrücke. Der Ausdruck stellt sicher, dass ein verstecktes Eingabe-Tag (das unser generiertes Token enthält) nur in Formulare mit einer Methode vom Typ eingefügt wird POST.
  • Wir müssen auch unsere Meta-Tags in die einfügen Header (Falls vorhanden). Dies ist einfach, da das schließende Tag nur einmal pro Datei vorhanden sein sollte.
  • Schließlich, da wir das verwenden display_override Hook, wird die Standardmethode zum Anzeigen Ihrer Ansicht nicht aufgerufen. Diese Methode beinhaltet alle möglichen Dinge, die wir nicht tun sollten - nur um Code einzufügen. Wenn wir es selbst nennen, wird das gelöst.

Schritt 6 - Haken

Zu guter Letzt müssen wir die Hooks selbst erstellen - also werden unsere Methoden aufgerufen. Fügen Sie den folgenden Code in Ihre ein system / application / config / hooks.php Datei:

// // CSRF-Schutzhaken, berühren Sie diese nicht, wenn Sie nicht wissen, was Sie // tun. // // DER AUFTRAG DIESER HAKS IST EXTREM WICHTIG !! // // DAS MUSS IN DER HOOK LIST von post_controller_constructor an erster Stelle stehen. $ hook ['post_controller_constructor'] [] = array (// Beachten Sie das "[]", dies ist nicht der einzige post_controller_constructor-Hook 'class' => 'CSRF_Protection', 'function' => 'validate_tokens', 'filename' = > 'csrf.php', 'filepath' => 'hooks'); // Generiert das Token (MUSS NACH DER BESTÄTIGUNG VORGESCHLAGEN WERDEN, ABER VOR DEM CONTROLLER // WIRD ES AUSGEFÜHRT, ANDERERWEISE NUTZT DER BENUTZER KEINEN ZUGANG ZU EINEM BESTIMMTEN FORMULAR). $ hook ['post_controller_constructor'] [] = array (// Beachten Sie das "[]", dies ist nicht der einzige post_controller_constructor-Hook 'class' => 'CSRF_Protection'), 'function' => 'generate_token', 'filename' = > 'csrf.php', 'filepath' => 'hooks'); // Dies injiziert Token in alle Formulare. $ Hook ['display_override'] = array ('class' => 'CSRF_Protection', 'function' => 'inject_tokens', 'filename' => 'csrf.php', 'filepath' => 'Haken');
  • Der erste Haken ruft die validate_tokens Methode. Dies ist nicht der einzige post_controller_constructor Haken, also müssen wir diese Klammern hinzufügen ("[]"). Weitere Informationen finden Sie in der Dokumentation zu CodeIgniter-Hooks.
  • Der zweite Haken, der auch a ist post_controller_constructor, generiert das Token für den Fall, dass es noch nicht generiert wurde.
  • Die dritte ist die Anzeigeüberschreibung. Dieser Haken wird unsere Marken in das Symbol einführen bilden und das Header.

Einpacken

Mit minimalem Aufwand haben wir uns eine schöne Bibliothek zusammengestellt.

Sie können diese Bibliothek in jedem Projekt verwenden und Ihre Site wird automatisch vor CSRF geschützt.

Wenn Sie zu diesem kleinen Projekt beitragen möchten, hinterlassen Sie bitte einen Kommentar oder verzweigen Sie das Projekt auf GitHub. Alternativ ist ab CodeIgniter v2.0 jetzt auch ein Schutz vor CSRF-Angriffen in das Framework integriert!