PHPIDS im Praxistest

Nachdem ich in letzter Zeit einiges über das Intrusion-Detection-System PHPIDS gelesen habe, habe ich es nun selbst einmal getestet. Hier meine bisherigen Erfahrungen:

Testumgebung
Für den Test habe ich Projekt genutzt welches sich derzeit noch in der Entwicklung befindet.
Das Projekt liegt lokal auf einem Thinkpad T42 (1,7Ghz und 2GB Ram) in einer XAMPP-Umgebung mit XDEBUG.

Installation / Integration
Zunächst müssen die PHPIDS-Dateien (es reicht das Verzeichnis “lib/IDS”) auf den Server geladen werden. Das Verzeichnis “IDS/tmp” benötigt Schreibrechte falls man dort Log- oder Cache-Files ablegen möchte. Anschließend müssen in der Datei Config.ini (IDS/Config) ein paar Einstellungen angepasst werden. Die Datei ist selbsterklärend, ich habe jedoch nur die Pfade angepasst da ich für meinen Test auf Logging oder Caching in einer Datenbank verzichtet habe.

Die Integration von PHPIDS in ein bestehendes Projekt hängt natürlich sehr stark vom Projekt selbst ab. In meinem Testfall werden sämtliche Anfragen per mod_rewrite auf die Datei index.php umgeleitet. Dort wird unter anderem eine Klasse security instanziert welche verschiedene Methoden zur Input-Validierung enthält. Eine dieser Methoden (validate_request) wird bei jedem Aufruf des Projektes ausgeführt und ist somit der ideale Ansatzpunkt für PHPIDS.
Das ist der hier relevante Teil der security-Klasse:

// include-path auf den Ordner mit IDS setzen:
ini_set('include_path', '/path/to/libs');
// IDS einbinden:
require_once 'IDS/Init.php';
// Array mit möglichen User-Inputs bilden:
$request = array(
	'REQUEST' => $GLOBALS['_REQUEST'],
	'GET' => $GLOBALS['_GET'],
	'POST' => $GLOBALS['_POST'],
	'COOKIE' => $GLOBALS['_COOKIE']
);
// IDS initialisieren:
$init = IDS_Init::init('/path/to/libs/IDS/Config/Config.ini');
// Caching ausschalten:
$init->config['Caching']['caching'] = 'none';
// Request-Array analysieren:
$ids = new IDS_Monitor($request, $init);
$result = $ids->run();
// Impact abfragen und ggf. reagieren:
if($result->getImpact() > 1)
{
	die('Hacking attempt detected. IP logged.');
}
// include-path auf seinen ursprünglichen Wert zurücksetzten:
ini_restore('include_path');

Was hier passiert ist schnell erklärt:
Es wird ein Array gebildet welches alle Variablen enthält die vom Benutzer beeinflusst werden können, etwa durch Formulareingaben oder Ähnliches. Der Inhalt dieses Arrays wird nun von PHPIDS auf mögliche Angriffsversuche untersucht. Mögliche Angriffe wären z.B. XSS oder SQL-Injection Attacken. Erkannte Angriffe werden von PHPIDS bewertet. Je “gefährlicher” oder “bedrohlicher” ein Angriff ist, desto höher ist der Impact-Wert. Im obigen Beispiel wird das Script sofort beendet sobald der Wert größer als 1 ist.

Performance
Aufgrund vieler regulärer Ausdrücke u.Ä. ist PHPIDS sicherlich nicht extrem Performant, aber es ist auch nicht extrem langsam. In meinen Test gab es nur einen Angriff der PHPIDS quasi in die Knie gezwungen hat. (Genaueres weiter unten) Ob man dieses Tool nun auf einer High-Performance Webseite einsetzen kann ist schwer zu sagen. Hier kommt es sicherlich auf die Server, das Caching und viele andere Dinge an.
Hier jedoch ein kurzer Vergleich der Methode validate_request mit und ohne PHPIDS (eingebunden wie oben beschrieben). Es handelt sich um einen einfachen Aufruf der Seite ohne dass irgendwelche Angriffe versucht werden.

Bei Standard-XSS-Angriffsversuchen wie man sie z.B. hier findet gehen die Zeiten leicht nach oben, bleiben aber immer im Rahmen. Hier das Ergebnis bei einem GET-Parameter mit folgendem Imhalt:

Einen Fall konnte ich jedoch finden, bei dem PHPIDS stark einbricht. Es handelt sich um einen SQL-Injection Angriff der kürzlich verwendet wurde um Javascript auf vielen Webseiten einzuschleusen. (Artikel bei heise.de)
Wird der String aus diesem Angriff per GET-Parameter übergeben steigt die Prozessorlast extrem an und das Script braucht lange für die Ausführung. Verantwortlich dafür sind 164 Aufrufe der Funktion preg_match die extrem lange brauchen. In meinem Test waren es über 4000ms.

Fazit
PHPIDS ist ein sehr nützliches Hilfsmittel um viele Angriffe auf Webprojekte zu erkennen. Die Installation ist kinderleicht und auch bei der Integration in ein bestehendes Projekt sollte es keine größeren Probleme geben.
Auf zwei Dinge möchte ich jedoch Hinweisen:
1. PHPIDS ist ein System zur Erkennung von Angriffen, es ist nicht dazu da sie zu verhindern oder zu blockieren. Diese Aufgabe muss ein Entwickler selbst übernehmen.
2. PHPIDS verwendet teilweise viele reguläre Ausdrücke welche resourcenhungrig sind. Bei High-Traffic Projekten sollte man deshalb ein Auge auf die Serverlast haben und sich das PHPIDS-Caching genauer anschauen.

9 thoughts on “PHPIDS im Praxistest

  1. Lars Strojny

    $_REQUEST kann man rauslassen, das ist redundant in GET, POST, COOKIE. Ansonsten kann ich nur empfehlen, ein generelles Größenlimit für alle Input-Daten festzulegen, über dem der Request komplett verworfen wird. Dadurch sinkt die Gefahr, durch den Einsatz von PHP IDS Opfer einer DOS Attacke zu werden. Interessant wäre auch mal zu schauen, ob man die regular expressions nicht in eine Große kompilieren kann, vielleicht hilft das.

  2. Mario Heiderich

    @Lars: Nope – $_REQUEST ist nicht redundant in GET, POST und COOKIE. Versucht ein Angreifer via HTTP Method Spoofing eine Applikation zu attackieren so kann ihm eine Umgehung von Systemen wie dem PHPIDS und anderen gelingen wenn diese lediglich GET, POST und COOKIES prüfen.

    Man kann das ganze relativ leicht selber ausprobieren indem man ein wenig mit dem XHR Objekt in der Firebug Konsole spielt – Beispielcode gerne auf Anfrage. Weiterhin ist folgender Link zu diesem Thema interessant:

    http://i8jesus.com/?p=23

    Was mich ein wenig wundert ist die hohe Auslastung bei dem auf heise.de geposteten Vektor – sicher dass die PHPIDS Version aus dem Test aktuell ist?

    VG,
    .mario

  3. Simon

    Für den Test habe ich Version 0.4.7 verwendet, sollte also aktuell sein. Allerdings ist es nicht wirklich verwunderlich das die Last nach oben geht. Der komplette String welcher in diesem Angriff verwendet wurde ist über 2200 Zeichen lang. Eine String dieser Länge 160 mal durch einen umfangreichen RegEx gejagt kann die Last schon mal nach oben treiben.

    Kurzer Nachtrag: Habe es gerade nochmal mit der aktuellen default_filter.xml getestet. Die Zeit liegt immer noch bei 3600ms.

    Es sind 9 Ausdrücke die eine Großteil der Zeit in Anspruch nehmen (siehe Textfile). Habe das hier allerdings nur mit mircrotime im Code selbst nachgemessen. Ist also nicht 100%ig genau.

    Textfile: Regeln mit entspr. Microtime

  4. Peter

    Mit welchem Tool hast du die Performance (in Millisekunden) gemessen? Du hast Ausschnitte von Screenshots angegeben, aber ich kann das Programm nicht erkennen. Würde gerne mehr über Performancemessung wissen.

    Viele Grüße aus der Eifel! 🙂

  5. Pingback: PHPIDS - Sicherheit f

  6. Pingback: PHP/MySQL: "SQL Injection" vermeiden - Seite 5 - php.de

  7. diesajad

    “@Lars: Nope – $_REQUEST ist nicht redundant in GET, POST und COOKIE. Versucht ein Angreifer via HTTP Method Spoofing eine Applikation zu attackieren so kann ihm eine Umgehung von Systemen wie dem PHPIDS und anderen gelingen wenn diese lediglich GET, POST und COOKIES prüfen.”

    Das halte ich für Unsinn. Kannst du das mal etwas genauer ausführen und mit Beispielen Belegen? Ich frage mich auch was XHR damit zu tun haben soll.

  8. Marc

    Ich lese hier gerade etwas über:
    “…..ein generelles Größenlimit für alle Input-Daten festzulegen….”

    Wo find ich Infomationen wie man das macht?

Leave a Reply

Your email address will not be published. Required fields are marked *

π