Rolf B: Wie kann PHP / SQL gleichzeitige Anfragen abwehren?

Beitrag lesen

Hallo Linuchs,

wenn Du DOS Attacken unterstellst, wäre zuerst einmal eine Anfrage bei deinem Hoster fällig, welche Maßnahmen er dagegen in seinem Portfolio hat. Vielleicht ist ja alles ganz einfach und nur einen kleinen Konfigurationseintrag entfernt.

Wenn Du Dich selbst wehren musst, tja. Ich hätte fast gesagt: Verwende die Session - PHP sorgt von sich aus dafür, dass immer nur ein Request an die Session herankommt. Aber wenn das ein Bot ist, dann wird er auch keinen Session-Keks mitbringen und dann nützt es nichts.

Das von Jörg genannte mod_evasive hat gewisse Probleme, die habe ich in meiner Antwort an ihn aufgezeigt. Grundsätzlich wäre dieses Modul eine gute Idee, praktisch muss man das validieren.

Eine andere manuelle Möglichkeit wäre, zu Beginn eines Requests eine Datei zu erzeugen, in deren Name die Absender-IP Adresse codiert ist, und diese Datei brutal zu locken. Kommt von der gleichen IP ein anderer Request herein, wird er durch den Lock blockiert und du kannst ihn mit HTTP Status 500 beantworten (oder Status 418, um den Bot zu verwirren). Endet der PHP Request, kannst Du die Datei schließen und löschen. Kleiner Nachteil: Falls Du tatsächlich mal in die Lage kommst, zwei Requeste für eine User parallel ausführen zu wollen, wirkt die Sperre auch dort. Und wenn Du von einer Bot-Farm geDDOSt wirst, hilft eine IP Sperre auch nichts. Ob das der Fall ist, kannst Du nur mit vollständiger Protokollierung aller Requests erkennen (die Du aber nicht zu lange speichern darfst, DSGVO sei Dank - kurzfristig sollte OK sein, weil die Analyse eines DOS-Angriffs ein berechtigtes Interesse ist).

Ich weiß nicht, wieviele der Attacken innerhalb 5 sec durchgelaufen sind, ohne eine Mail auszulösen.

Sorry - aber das kann es nicht sein. Der Webserver sollte jeden Request loggen; als Serverbetreiber musst Du darauf zugreifen können.

Eine dritte Möglichkeit kann sein, die Ermittlung größerer Datenmengen grundsätzlich nach einer gewissen Zeit abzubrechen. Verwende eine Abbruchzeit, in der die Requeste NORMALERWEISE erfolgreich durchlaufen.

Eine weitere Möglichkeit könnte mysqli_options(MYSQLI_OPT_CONNECT_TIMEOUT) sein. Ich würde nämlich unterstellen (was Du natürlich erstmal untersuchen müsstest), dass der Zeitfresser der Connect zur DB ist, weil die Maximalzahl der Connections überschritten wird und die Folge-Connects in einer Queue laden. Dafür musst Du allerdings den Connect zur DB etwas modifizieren. Statt einem einzigen Aufruf mysqli_connect (bzw. new mysqli()) verwendest Du

$db = mysqli_init();
if (!$db) { /* fail */ }
if (!$db->options(MYSQLI_OPT_CONNECT_TIMEOUT, 2)) { /* fail */ }
if (!$db->real_connect($host, $user, $password, $database)) { /* fail */ }

Das geht natürlich auch mit dem funktionalen Interface (mysqli_options, mysqli_real_connect). Falls dein altehrwürdiger Betrieb noch mit mysql arbeitet (ich glaube, da war was), musst Du vor dem Connect mittels ini_set die Option mysql.connect_timeout passend setzen.

Auf diese Weise würdest Du auf einen Fehler laufen, wenn der Connect länger als 2 Sekunden dauert. Diese Connection-Zeit wirst Du im Normalbetrieb nie erleben.

Rolf

--
sumpsi - posui - obstruxi