Werbung ohne AdBlocker entfernen

Werbung auf Webseiten auszufiltern ist aus Sicht der Computersicherheit ein unbedingtes muss. Dem Einschleusen von Schadsoftware in die Werbenetzwerke scheinen derzeit keine großen Hürden entgegen gesetzt zu sein und ebenso scheint es, dass das von Kriminellen auch ausgenutzt wird. In den einschlägigen Medien findet man regelmäßig Berichte zu diesem Thema. Ein Grund warum jeder mindestens einen „AdBlocker“ installiert haben sollte. Eine weitere Möglichkeit bietet das Umleiten bekannter „WerbeURLs“ auf eine andere Zieladresse.

Um „WerbeURLs“ auf einen eigenen Webserver oder localhost umzuleiten kann man an mehrern Stellen ansetzen:

  • Die /etc/hosts Datei,
  • der zentrale DNS-Server in einem Netzwerk, sofern dieser unter der eigenen Kontrolle steht und
  • der eigene Router.

Hinweis: Das Umleiten bzw. Blockieren von Werbeinhalten in einem Netzwerk stellt eine Zensur dar. Hier müssen rechtliche Vorgaben und Einschränkungen beachtet werden. Ein Umsetzen der hier vorgestellten Techniken sollte gerade in einem Unternehmensumfeld rechtlich geprüft werden!


Die Umsetzung

Bei der Recherche zum Thema „Blockieren von Werbung“ bin ich auf eine Seite gestoßen, die eine sehr umfangreiche Liste mit bekannten „AdServern“ in verschiedenen Formaten erstellen kann: https://pgl.yoyo.org/adservers/.

Zur Vertrauenswürdigkeit dieser Seite kann ich leider nichts sagen, es scheint sich um ein rein privates Projekt zu handeln. Auch zur Korrektheit der Daten liegen mir keine Informationen vor. Die Benutzung dieser Quelle erfolgt also auf eigene Gefahr. Das hier im Weiteren beschriebene Vorgehen kann sicherlich auch mit Blacklisten aus anderen Quellen umgesetzt werden.

Basierend auf den erzeugten Listen kann dann die Blockierung von Werbung in einer der drei Varianten umgesetzt werden. Bei den ersten beiden Varianten empfiehlt es sich einen eigenen kleinen Webserver laufen zu lassen, der eine leere Seite zurück liefert. Ist kein Webserver erreichbar, wird im Browser unter Umständen ein Fehler an den Stellen wo die Werbeeinblendungen sein sollen angezeigt.

/etc/hosts

Die Datei /etc/hosts ist in einem unixartigen System die erste Anlaufstelle für das Übersetzen von Dateinamen in IP-Adressen. Wenn beispielsweise eine Webseite in einem Browser aufgerufen wird, schaut das Betriebssystem zunächst in dieser Datei nach, ob der Name in der Adresse (URL) hier einer IP-Adresse zugeordnet werden kann. Ist das der Fall, wird dem aufrufenden Programm diese IP mitgeteilt. Das können wir uns zunutze machen um einfach allen bekannten „AdServer“ hier der IP-Adresse 127.0.0.1 (das ist immer der eigene Rechner) zuzuordnen. Über die oben genannte URL kann mittels eines Formulars eine Liste im Format für die /etc/hosts erzeugt werden. Diese Liste kann dann nach einer Überprüfung (evtl. könnte sich das ja etwas ungewolltes einschleichen) komplett in die Zwischenablage kopiert werden und dann in die Datei /etc/hosts auf dem eigenen Rechner eingefügt werden. Direkt nach dem abspeichern kann das getestet werden, dazu den möglicherweise installierten „AdBlocker“ im Browser deaktivieren und eine Seite aufrufen, von der man weiß dass diese viel Werbung enthält.

Die Einträge sollte man in regelmäßigen Abständen aktualisieren. Dabei ist darauf zu achten, dass nur die über die Liste hinzugefügten Einträge ausgetauscht werden. Bereits bestehende Einträge (also Einträge die vor der Ergänzung mit der Liste schon da sind) müssen bestehen bleiben, da es sonst zu Problemen kommen kann.

bind

Verwaltet man in einem Netzwerk einen eigenen DNS-Server, in diesem Beispiel einen bind9, kann das ganze auch zentral für ein gesamtes Netzwerk umgesetzt werden. Grundlage für die Umsetzung mit bind ist auch wieder die über die oben Genannte Webseite erzeugte Liste. Zu beachten ist, dass das Format für bind eingestellt sein muss. Die erzeugte Liste muss nun in einer Datei im Konfigurationsverzeichnis des bind abgelegt werden. Nennen wir diese Datei der Einfachheit „adblock“. In der Datei ist in jedem Eintrag eine Zonendatei definiert. Eine solche Zonendatei muss entsprechend auch noch angelegt werden. Die Liste die in der Datei „adblock“ enthalten ist kann mit einem „include“ in der bind-Konfiguration eingebunden werden. Im folgenden gehe ich davon aus, dass die bind Konfigurationsdateien im Verzeichnis „/etc/bind“ liegen (ggf. den Pfad anpassen).

Die bind Konfiguration

Der Include unserer Liste wird in der Datei „named.conf“ bzw. „named.conf.local“ vorgenommen. Der Eintrag sieht wie folgt aus:

include "/etc/bind/adblock"

Die in der Liste definierte Zonendatei heißt „null.zone.file“. Diese muss einmalig angelegt werden.

$TTL    604800
@   IN  SOA ns.yourdomain.com. hostmaster.yourdomain.com. (
                1       ; Serial
                        604800      ; Refresh
            86400       ; Retry
            2419200     ; Expire
            604800 )    ; Negative Cache TTL
                        NS        your.name.server.tld
                        A         your.web.server.tld
@   IN  A   webserverip
*       IN      A       webserverip

Nach dem einbinden der Liste sowie der neuen Konfiguration und dem Neustart fiel auf, dass der bind9 die in der Liste referenzierte Zonendatei nicht finden konnte. Das ersetzen des Namens der Zonendatei gegen den Namen und den vollständigen Pfad führte dann zum Erfolg.

Automatisierung

Um möglichst wenige Aufwand bei der Aktualisierung der „adblock-Liste“ zu haben kann das ganze auch automatisiert werden.


Hinweis: Da hier Daten von einem externen System eingebunden werden, sollten diese in jedem Fall vor der Einbindung in den eigenen Nameserver überprüft werden. Die Automatisierung ermöglicht es auf einfachem Wege DNS-Einträge zu manipulieren!


Das erzeugen der Liste kann auch über die URL gesteuert werden. Hier können die benötigten Parameter einfach mit angegeben werden. Die URL kann dann mit curl aufgerufen und in einer temporären Datei zwischengespeichert werden werden. Mit sed wird dann der Pfad zu der Zonendatei angepasst werden. Idealerweise wird das alles in einem Skript zusammengefasst, welches über cron aufgerufen wird:

#!/bin/bash

################################################################################
#                                                                              #
# Author: Patrick Ditzel                                                       #
# Lizenz:  GNU GENERAL PUBLIC LICENSE v3                                       #
#                                                                              #
################################################################################

################################################################################
#                                                                              #
# Konfiguration über Variablen                                                #
#                                                                              #
################################################################################
#
# Wie soll die AdServer-Liste heißen und wo abgespeichert werden
TARGETFILE=/etc/bind/adblock

# Absendeadresse für E-Mail
SENDER=sender@email-address.com

# Empfängeradresse für E-Mai
RCPT=rcpt@email-address.com

################################################################################
#                                                                              #
# Ab hier nichts mehr ändern ;-)                                               #
#                                                                              #
################################################################################

TMPFILE1=/tmp/tmp1.adserver.lst

TMPFILE2=/tmp/tmp2.adserver.lst

OLDTARGETFILE="${TARGETFILE}.1"

CHECKMSG=""

DIFFS=""

DIFFSTAT=false
################################################################################
#                                          #
# Funktionen des Programmes                            #
#                                          #
################################################################################

function get_list () {
    # AdServer-Liste herunterladen
    curl -o $TMPFILE1 "https://pgl.yoyo.org/adservers/serverlist.php?hostformat=bindconfig&showintro=0&startdate%5Bday%5D=01&startdate%5Bmonth%5D=01&startdate%5Byear%5D=2000&mimetype=plaintext"
}

function prepare_list () {
    # Test ob AdServerList bereits vorhanden ist
    if [ -s $TMPFILE1 ]; then
        # AdServerliste bearbeiten:
        ## null.zone.file gegen /etc/bin/null.zone.file tauschen, da sonst die Liste nicht in bind geladen werden kann
        ## Alle einträge die das Wort zone beinhalten rausfiltern und in eine eigene Daten schreiben
        sed 's!null.zone.file!/etc\/bind\/null.zone.file!' $TMPFILE1 | grep zone > $TMPFILE2
    else
        echo "Datei $TMPFILE1 ist nicht vorhanden" | mailx \-r "$SENDER" \-s "Datei nicht gefunden" "$RCPT"
        exit 1
    fi
}

function check_list () {
    if [ -s $TMPFILE2 ]; then
        while read LINE; do
            # Zeilenweise nach Einträgen suchen, die nicht den Namen der Zonendatei enthalten
            echo $LINE | grep -v "null.zone.file"
            # Wird ein solcher Eintrag gefunden, wird dieser in die Variable $CHEKCMSG geschrieben
            if [ "$?" -eq 0 ]; then
                CHECKMSG="$CHECKMSG Entry found not targeting to null.zone.file:\n $LINE \n --- --- ---\n" 
            fi
        done < $TMPFILE2 
        # Wenn die Variable $CHECKMSG nicht leer ist, ... 
        if [ -n "$CHECKMEG" ]; then
            # ... via E-Mail über das Ergebnis informiert.
            echo $CHECKMSG | mailx \-r "$SENDER" \-s "Nicht konforme Einträge in der AdBlock DNS-Liste gefunden" "$RCPT"
            exit 1
        fi
    else
        echo "Die Datei $TMPLIST2 ist nicht vorhanden" | mailx \-r "$SENDER" \-s "Datei nicht gedunden" "$RCPT"     
        exit 1
    fi
}

function compare_lists () {
    if [ -s $TMPFILE2 ] && [ -s $TARGETFILE ]; then
        # Unterschieden sich die neue Datei und die bestehende Datei
        diff $TMPFILE2 $TARGETFILE
        # Wenn ja, dann ...
        if [ "$?" -ne 0 ]; then
            # STATUS der Überprüfung in eine Variable schreiben
            DIFFSTAT=true
            # Änderungen in eine Variable schreiben und ...
            DIFFS="diff newBlacklsit existingBlacklist: "
            DIFFS="$DIFFS `diff $TMPFILE2 $TARGETFILE`"
            DIFFS="$DIFFS --- --- --- "
            # ... per E-Mail versenden
            echo $DIFFS | mailx \-r "$SENDER" \-s "Aenderungen an der DNS Blackliste" "$RCPT"   
        fi
    else
        if [ ! -s $TMPFILE1 ]; then
            echo "Datei $TMPFILE1 ist nicht vorhanden." | mailx \-r "$SENDER" \-s "Datei nicht gefunden" "$RCPT"
        fi
        if [ ! -s $TMPFILE2 ]; then
            echo "Die Datei $TMPLIST2 ist nicht vorhanden." | mailx \-r "$SENDER" \-s "Datei nicht gefunden" "$RCPT"
        fi
        exit 1
    fi
}

function renew_list () {
    # Bestehende Datei wegsichern, wenn vorhanden
    if [ -e $TARGETFILE ] && [ "$DIFFSTAT" == true ]; then
        cp $TARGETFILE $OLDTARGETFILE
    fi
    # Datei aktualisieren
    if [ -s $TMPFILE2 ]; then  
        if [ "$DIFFSTAT" == true ]; then
                mv $TMPFILE2 $TARGETFILE
        fi
    else
        echo "Die Datei mit den Quelldaten ( $TEMPFILE2 ) ist entweder nicht vorhanden oder leer." | mailx \-r "$SENDER" \-s "Datei nicht gefunden" "$RCPT"
        exit 1
    fi
    # neue Liste in bind laden
    if [ "$DIFFSTAT" == true ]; then
        rndc reload
    fi
    # Aufräumen
    rm -f $TMPFILE1 $TMPFILE2
}

function check_root () {
    if [ "$USER" != "root" ]; then
        echo "Sie haben nicht ausreichende Berechtigungen um das Programm erfolgreich auszuführen. Bitte lassen Sie das Programm als Benutzer root laufen." | mailx \-r "$SENDER" \-s "Fehlende Berechtigungen" "$RCPT"
        exit 1
    fi
}

################################################################################
#                                          #
# Das Hauptprogramm                                #
#                                          #
################################################################################

get_list
prepare_list
check_list
compare_lists
check_root
renew_list

Optimal ist das Skript unter Sicherheitsaspekten nicht. Es wird lediglich zeilenweise überprüft ob ein Eintrag existiert, in dem nicht die Zeichenkette „null.zone.file“ vorkommt. Ist dies der Fall werden diese Einträge gesammelt und via E-Mail an den am Anfang des Skriptes definierten Empfänger gesendet. Zudem wird die Abarbeitung des Skriptes abgebrochen, so dass kein nicht konformer Eintrag in die bind-Konfiguration geladen werden kann.

Zudem wird auch noch die bestehende und die neue Datei mit den Blacklisteinträgen verglichen und alle Änderungen via E-Mail mitgeteilt. Das fordert jedoch das initial sämtliche Einträge manuell geprüft werden müssen.

Für das Verschieben der neuen Blacklistdatei in das Konfigurationsverzeichnis des bind und das Neueinlesen der neuen Konfiguration des binds sind root-Rechte notwendig. Das Skript prüft vor Aufruf der entsprechenden Funktion ob diese Rechte vorhanden sind. Falls nicht bricht es ab und informiert per E-Mail.

Das Skript und die null.zone.file sind auch hier zu finden.

Der eigene Router

Viele Router bieten die Möglichkeit bestimmte Adresse über eine Blacklist zu blockieren. In der Regel reicht dafür ein Domain- oder Servername. Diese Namen können aus den Listen entsprechend extrahiert werden – beispielsweise kann aus der Liste für die /etc/hosts für jeden Eintrag die Ziel-IP-Adresse entfernt werden und diese resultierende Liste dann in den Router eingetragen werden.

Zu dem Argumenten der Seitenbetreiber, dass …

… ohne die Werbung langfristig keine kostenlosen Inhalte mehr angeboten werden können. Klar, das ist ja deren Geschäftsmodell. An dieser Stelle müssen diese Betreiber deren Seitenbesuchern auch zu jedem Zeitpunkt garantieren können, dass die eingeblendete Werbung keine schädlichen Bestandteile hat. Um das zu können müssen jedoch viele Leute genau dafür beschäftigt werden, die eingespielte Werbung auf schädliches Verhalten zu prüfen. Das kostet dann wahrscheinlich soviel, dass es über die Werbeeinnahmen nicht mehr finanziert werden kann. Wie auch immer: AdBlocker und Werbefilter sind „digitale Selbstverteidigung“!