Trackbackspam mit PHP verhindern

Im September des letzten Jahres habe ich bereits einmal über eine Möglichkeit zum erkennen von Trackbackspam geschrieben. Diese Funktion habe ich nun noch etwas verfeinert und einen zusätzlichen Check eingebaut.

Damit ein Trackback nicht als Spam identifiziert wird, müssen zwei Bedingungen erfüllt sein.

Zum einen muss die Seite die den Trackback sendet, einen Link auf meine Seite haben. Klingt logisch, denn warum sonst sollte man einen Trackback versenden. Das kommt immer mit einem Link zusammen. Nur durch dieses Kriterium filtert man schon einen Grossteil von dem Spamnachrichten, denn die Webseiten der Spamer haben selten einen Backlink auf die eigene Seite.

Die andere Bedingung ist, dass die IP Adresse der Webseite, die angegeben wird, dieselbe sein muss wie die des Servers der den Trackback sendet. Erhalte ich also einen Trackback mit der URL test.ch muss der Trackback auch von dem Server gesendet werden, auf dem test.ch liegt. Mal abgesehen von NAT.

Um zu überprüfen, ob die Webseite einen Link auf die eigene Seite gesetzt hat, muss man den Inhalt der anderen Webseite auslesen und diesen nach einem Link absuchen. In dieser Funktion suche ich nur nach dem String t-error.ch und das erkennt auch die meisten Spamnachrichten.
Der Vergleich der IP-Adresse ist auch relativ simpel. Mit der Funktion getHostbyName() löst man die IP Adresse der URL auf und die IP Adresse des Servers der den Trackback sendet, kann man man mit $_SERVER['REMOTE_ADDR'] auslesen.

Und so sieht die Funktion dann aus.
<?
function trackbackSpamCheck($url)
{
    
// trackback prinzipiell als spam definieren
    
$spam=TRUE;
    
    
// URL in einzelteile zerlegen
    
$url=parse_url(trim(addSlashes($url)));
    
    
// verbindung zum host auf port 80 herstellen
    
$fp=fSockOpen($url['host'],80,$errno,$errstr,30);
    
    
// ueberpruefen, ob die verbindung steht
    
if($fp)
    {
        
// pfad zur zieldatei auslesen
        
$path=$url['path'];
        if(isSet(
$url['query']))
        {
            
$path.="?".$url['query'];
        }

        
// wenn der pfad leer ist '/' verwenden
        
if($path=="")
        {
            
$path="/";
        }

        
// get request an den server senden
        
$req ="GET ".$path." HTTP/1.0\r\n";
        
$req.="Host: ".$url['host']."\r\n\r\n";
        
fPuts($fp,$req);

        
// http headers auslesen
        
while(!feof($fp))
        {
            
$data=fgets($fp,1024);
            if(
trim($data)=="")
            {
                break;
            }
        }

        
// daten auslesen
        
while(!feof($fp))
        {
            
$data=fgets($fp,1024);
            
            
// ueberpruefen, ob t-error.ch darin vorkommt
            // dies kann man noch verfeinern,
            // in dem man nach einem link sucht
            
if(eregi("t-error.ch",$data))
            {
                
$spam=FALSE;
                break;
            }
        }
        
        
// verbindung zum server trennne
        
fclose($fp);
    }

    
// ip adresse des hosts auslesen,
    // auf dem die im trackback angegebene
    // webseite liegt
    
$ip=@getHostByName($url['host']);

    
// ueberpruefen, ob die ip adresse
    // aufgeloest werden konnte.
    // trackback sonst als spam definieren
    
if($ip==$url['host'])
    {
        
$spam=TRUE;
    }
    else
    {
        
// ip adresse der webseite
        // mit der ip des hosts,
        // welcher den trackback gesendet
        // hat vergleichen
        
if($_SERVER['REMOTE_ADDR']!=$ip)
        {
            
$spam=TRUE;
        }
    }
    
    
// spam status zurueckgeben    
    
return $spam;
}
?>

Trackbackspam verhindern

In letzter Zeit hatte ich, wie schonmal schonmal berichtet, vermehrt Trackbackspam. Für das Problem mit dem Kommentarspam habe ich eine gute Lösung gefunden. Seit der Einführung der Matheaufgabe, hatte ich keinen Spamkommentar mehr. Bei den Trackbacks ist das ja nicht so einfach, aber es gibt trotzdem eine recht zuverlässige Lösung.
Wenn ich von einer Seite einen Trackback erhalte, dann sollte auf dieser Seite auch ein Link auf meine Seite sein, oder sie sollte zumindest erwähnt werden. Und genau das überprüft diese Funktion.
Nun habe ich eine kleine PHP Funktiongeschrieben, welche überprüft ob auf der fremden Seite meine URL Vorkommt. So reicht eine Überprüfung des Strings t-error.ch schon. Ich muss nicht mal überprüfen, ob es ein Link ist, denn die Trackbackspammer erwähnen auf ihren Seiten meine Seite ja kaum. Die Funktion überprüft die Seite in der Variable $url und gibt die Variable $spam zurück. Relativ simpel und effektiv. Bisher wurde noch kein Trackbackspam durchgelassen.
<?
function trackbackSpamCheck($url)
{
    
// Spamvariable
    
$spam=1;

    
// die url aufsplitten
    
$parsed=parse_url(trim(addSlashes($url)));

    
// einen pfad angeben wenn noetig
    
if(!isSet($parsed['path']))
    {
        
$parsed['path']="/";
    }

    
// den querystring anfuegen wenn noetig
    
$path=$parsed['path'];
    if(isSet(
$parsed['query']))
    {
        
$path.="?".$parsed['query'];
    }

    
// zum host verbinden
    
$fp=fSockOpen($parsed['host'],80,$errno,$errstr,30);
    if(
$fp)
    {
        
// GET request senden
        
fPuts($fp,"GET ".$path." HTTP/1.0\r\n");
        
fPuts($fp,"Host: ".$parsed['host']."\r\n\r\n");

        
// Den Quelltext auslesen
        
while(!fEof($fp))
        {
            
// auf t-error.ch pruefen
            
if(eregi("t-error.ch",fgets($fp,1024)))
            {
                
// wenn vorhanden $spam auf 0 setzen und abbrechen
                
$spam=0;
                break;
            }
        }

        
// verbindung trennen
        
fclose($fp);
    }
    
    return 
$spam
}
?>

Vermehrt Trackback-Spam

In letzter Zeit wird mein Blog vermehrt von Trackbackspam heimgesucht. Das Ziel sind zwei verschiedene Beiträge in diesem Blog, die Nachrichten auch immer etwa dieselben. Der Link verwiest zu einem Forum, wo man auf eine "Pharmacy" Seite umgeleitet wird. Momentan sind es nur um die fünf Trackbacks pro Tag und ich kann die auch Problemlos löschen. Allerdings wird es ja doch recht nervig. Vor allem, wenn in Zukunft immer mehr kommen sollten. Und das Sperren von Trackbacks bei diesen Beiträgen ist ja auch keine langfristige Lösung.
Momentan fällt mir nur eine langfristige Lösung ein. Und zwar kann man die Seite nach einem Link zur eigenen Seite absuchen. Falls dieser nicht vorhanden ist kann man den Trackback moderieren lassen oder gleich ganz Löschen. Oder kennt jemand noch eine andere effektive Variante?

Trackbacks mit PHP senden

Trackbacks werden über POST Requests versendet. Mit PHP ist das nicht weiter schwierig, da es die nette Funktion fsockOpen() gibt. In einem Trackback werden vier Variabeln an den anderen Server gesendet. Zuerst den Titel ($title), die URL zum eigenen Artikel ($url), den Text auch Excerpt genannt ($excerpt) und schlussendlich noch den Namen des eigenen Blogs ($blog_name).
Bevor wir nun die Verbindung zum fremden Server herstellen, formen wir zuerst mal die Variabeln richtig. Für einen POST Request muss man den Hostnamen und den Pfad zur Trackback Seite haben. Diese Adresse Teilt man am besten mit der Funktion parse_url() auf. Das Codestücklein sieht dann so aus:
<?
// adresse parsen
$trackback_url=parse_url($trackback_url);

// host und pafd variabeln
$host=$trackback_url['host'];
$url=$trackback_url['path'];

// wenn eine query (?...) gesetzt ist.
if(isSet($trackback_url['query']))
{
    
$url.="?".$trackback_url['query'];
}
?>

Nun setzten wir die Variable $text. Darin werden die zu sendenden Daten gespeichert. Die Variabeln müssen noch mit urlEncode() behandelt werden.
<?
$text 
="title=".urlEnCode($title);
$text.="&amp;url=".urlEnCode($url);
$text.="&amp;excerpt=".urlEncode($excerpt);
$text.="&amp;blog_name=".urlEncode($blog_name);
?>

Nun sind die Variabeln vorbereitet und wir können den Request senden.
<?
// verbindung zum host auf port 80 herstellen
$fp=fSockOpen($host,80);

// POST request mit HTTP/1.1
fPuts($fp,"POST ".$url." HTTP/1.1\r\n");

// Nochmals den Hostnamen angeben
fPuts($fp,"Host: ".$host."\r\n");

// Content-Type
fPuts($fp,"Content-Type: application/x-www-form-urlencoded; charset=utf-8\r\n");

// Laenge des Requests. Laesst sich mit strLen() wunderbar berechnen.
fPuts($fp,"Content-length: ".strLen($text)."\r\n");

// Verbidung danach wieder schliessen
fPuts($fp,"Connection: close\r\n\r\n");

// Daten senden
fPuts($fp,$text);

// Vrebindung trennen
fclose($fp);
?>

Das wars auch schon. Das ganze ist relativ simpel, allerdings muss man aufpassen, dass man die Variabeln richtig zurechtbiegt, damit keine Fehler auftreten. Bald folgt noch ein Beitrag über Autodiscovery, aber damit muss ich mich selber zuerst beschäftigen.

Anmerkung:
Bei den gesendeten Daten sollte nicht &amp; sondern nur & stehen. Das ist ein Problem der Software. Ich werde sehen, ob ich das noch zurechtbiegen kann.

XMLRPC-Calls mit PHP lesen

Jetzt habe ich endlich mal herausgefunden, wie man XMLRPC-Calls mit PHP entgegennimmt. Nicht mit $_POST oder $_GET. Sondern ganz einfach (wenn man es mal weiss) mit readfile("php://input");. Eine andere Variante ist die Umgebungsvariable $HTTP_RAW_POST_DATA. Schlimm, dass ich so lange hatte um das rauszukriegen.
Nun stehen Trackbacks zu meiner Seite nicht mehr viel im Weg. Ich muss nur noch rausfinden, wie man diese Daten am besten in einen Komemntar umwurstelt, aber das kriege ich auch noch raus.