Achim Janowski: Formulare / Absende-Intervall zum Schutz vor Massenspam

Hallo!

Vor kurzem habe ich hier (unter anderem) zweierlei gelesen:

1. Dass es PHP-Monkeys gibt - zu denen gehöre ich wahrscheinlich... ;-)

2. Dass bei Formularen eine Sperre nützlich ist, damit man nicht per Script zig oder mehr Mails innerhalb kürzester Zeit losjagen kann.

Das habe ich zur Zeit mal so gelöst, dass im Verzeichnis "formulare" eine kleine Datei mit dem Dateinamen "IP ohne Punkte" erstellt und überprüft wird:

$ip = getenv("REMOTE_ADDR");
$ip = str_replace(".", "", $ip);
if (file_exists("formulare/$ip")) {
  $erstellung = filemtime("formulare/$ip");
  $testzeit = time();
  if ($testzeit - $erstellung < 60) {
    echo "Fehler...";
    exit;
  }
}
$jp = fopen("formulare/$ip","w");
fclose($jp);

Bei meinen Tests funktioniert das tadellos. Mindestintervall zwischen zwei Aufrufen ist 60 Sekunden, sonst gibt's ne Fehlermeldung.

Nun meine Fragen:
Reicht die Überprüfung der IP?
Und ist das ein gangbarer Weg, viele kleine Dateien zu erzeugen - oder ist das völlig daneben?

Viele Grüße, Achim

    1. Dass bei Formularen eine Sperre nützlich ist, damit man nicht per Script zig oder mehr Mails innerhalb kürzester Zeit losjagen kann.

    Das habe ich zur Zeit mal so gelöst, dass im Verzeichnis "formulare" eine kleine Datei mit dem Dateinamen "IP ohne Punkte" erstellt und überprüft wird:

    Reicht die Überprüfung der IP?

    In der Regel schon. Darauf als einzigen Schutz zu bauen, ist allerdings weniger klug. Als erstes sollte immer die Funktion selber überprüft werden, in Deinem Beispiel: Ist es überhaupt notwendig, einen frei zugänglichen Mailversand anzubieten? Schließlich hat so ziemlich jeder Zugang zu eigenen Möglichkeiten.

    Und ist das ein gangbarer Weg, viele kleine Dateien zu erzeugen - oder ist das völlig daneben?

    Ziemlich daneben :) Jede Deiner Dateien verbraucht mindestens das hundertfache seiner Informationsgröße an Plattenplatz. Öffne lieber eine einzelne Datei, der Aufwand ist nicht viel größer. Du kannst statt "Datei roh" auch die dbm-Funktionen verwenden, dann wird's noch einfacher.

    Gruß,
      soenk.e

    1. Hallo!

      Danke erstmal für Deine Antwort!

      Als erstes sollte immer die Funktion selber überprüft werden, in Deinem Beispiel: Ist es überhaupt notwendig, einen frei zugänglichen Mailversand anzubieten? Schließlich hat so ziemlich jeder Zugang zu eigenen Möglichkeiten.

      Es geht mir auch darum, dass ich nicht über das Formular "zugeballert" werden...

      Öffne lieber eine einzelne Datei, der Aufwand ist nicht viel größer. Du kannst statt "Datei roh" auch die dbm-Funktionen verwenden, dann wird's noch einfacher.

      Hmm, den Gedanken hatte ich auch schon, bin aber leider bei der Umsetzung irgendwie stecken geblieben.

      Würde es so gehen?
      1. Die Logdatei öffnen und als String einlesen. Durchsuchen, ob ein Teilstring namens $ip drin ist. Wenn ja, den dahinter stehenden Timestamp auslesen. Timestamp mit aktuellem Timestamp Zeit vergleichen. Wenn nötig, innerhalb des Strings mit str_replace den alten Timestamp durch den neuen ersetzen. String in die Datei zurückschreiben und Datei schließen.

      2. Mit fopen, fgets, fseek, fputs... arbeiten.

      Oder ist das auch wieder daneben?

      Achim

      1. Als erstes sollte immer die Funktion selber überprüft werden, in Deinem Beispiel: Ist es überhaupt notwendig, einen frei zugänglichen Mailversand anzubieten? Schließlich hat so ziemlich jeder Zugang zu eigenen Möglichkeiten.

        Es geht mir auch darum, dass ich nicht über das Formular "zugeballert" werden...

        Gut, auch wenn gegen eine Sperre nichts einzuwenden ist, kommt der Fall, wo ein Formular mit _festgelegtem_ Empfänger quasi als Mailbomb mißbraucht wird, doch eher selten vor. Einzige Ausnahme: Die allseits beliebten "Votes", die auf keiner Mein-Haus-Mein-Hund-Meine-Freundin-Homepage fehlen dürfen ;)

        Würde es so gehen?

        1. Die Logdatei öffnen und als String einlesen. Durchsuchen, ob ein Teilstring namens $ip drin ist. Wenn ja, den dahinter stehenden Timestamp auslesen. Timestamp mit aktuellem Timestamp Zeit vergleichen. Wenn nötig, innerhalb des Strings mit str_replace den alten Timestamp durch den neuen ersetzen. String in die Datei zurückschreiben und Datei schließen.

        Das wäre das, was ich mit "Datei roh" meinte. Da Du allerdings bei jedem Öffnen der Datei alte Einträge rausschmeißen mußt (damit die Datei nicht in's Unermessliche wächst), wäre es vielleicht sinnvoll, zeilenweise einzulesen und ein echtes Feld aufzubauen:

        if (! $datei=fopen("sperrliste","a+"))
            {
             $verboten=true;
            }
           else
            {
             // Dateiformat: 'ip\tzeit\n'
             fseek($datei,0);
             while (!feof($datei))
               {
                $a=explode("\t",rtrim(fgets($datei))); // einlesen und aufspalten
                if ($a[1]>time()-5*60)   // wenn weniger als fünf Minuten..
                   $sperrliste[$a[0]]=$a[1]; // ..merken
               };
             $verboten=isset($sperrliste[$_SERVER["REMOTE_ADDR"]]);
             $sperrliste[$_SERVER["REMOTE_ADDR"]]=time();
             fseek($datei,0);
             foreach ($sperrliste as $sperre)
               fputs($datei,$sperre[0]."\t".$sperre[1]."\n");
             fclose($datei);
            };

        if ($verboten)
            {
             header("HTTP/1.0 403 Forbidden");
             echo "Annahme verweigert, bitte später nochmal probieren.";
            }
           else
            {
             echo "Danke blabla";
            };

        So in dem Dreh, eben aus den Fingern gesogen, Fehler schenk ich Dir zum Basteln :)

        Gruß,
          soenk.e