Kontakt für Domain-Missbrauch mit C# von abuse.net ermitteln 👍 👎

In meinem vorherigen Beitrag habe ich bereits ein paar allgemeine Gedanken und Lösungsansätze zum – leidigen – Thema Spam niedergeschrieben. In diesem Beitrag soll es, wie bereits angekündigt, darum gehen, den bereits kurz beschriebenen Dienst von abuse.net automatisiert (mit C#) anzusprechen.

Der Anbieter stellt alle wesentlichen Informationen zur Umsetzung zur Verfügung. Dort wird der Zugriff per DNS oder Whois beschrieben. Das Herunterladen der (Roh-)Daten ist jedoch nicht möglich. Beachtet bitte außerdem die Nutzungsbedingungen, so ist der kommerzielle Einsatz beispielsweise nicht ohne Weiteres gestattet.

Es werden bei den folgenden beispielhaften Implementierungen lediglich die ermittelten eMail-Adressen an sich zurückgeliefert und keine – ebenfalls verfügbaren – Kommentare, welche insbesondere Angaben zur Quelle enthalten. Des Weiteren findet keine Reduzierung von Duplikaten statt. Beides kann bei Bedarf aber selbstverständlich noch angepasst bzw. ergänzt werden. Die Methoden sind darüber hinaus variadisch und können daher mit mehreren Argumenten (oder einem Feld) aufgerufen werden.

Zugriff per Whois

Eine – auch mit .NET-Bordmitteln – sehr einfache Möglichkeit der Abfrage des für Missbrauch zuständigen Kontakts zu einer Domain ist das Whois-Protokoll. Die Abfrage erfolgt per TCP bei whois.abuse.net:43.

Zugriff per Whois
01020304050607080910111213141516171819202122
public static IEnumerable<string> GetAbuseContactList(params string[] domainList) {    using(TcpClient client = new TcpClient("whois.abuse.net", 43)) {        using(NetworkStream stream = client.GetStream()) {            byte[] request = Encoding.UTF8.GetBytes(String.Join(" ", domainList) + "\r\n");            stream.Write(request, 0, request.Length);
using(StreamReader streamReader = new StreamReader(stream)) { while(!streamReader.EndOfStream) { string response = streamReader.ReadLine();
if(response.Contains("(")) { response = response.Substring(0, response.IndexOf('(')); }
if(!String.IsNullOrWhiteSpace(response)) { yield return response.Trim(); } } } } }}

Es sei jedoch darauf hingewiesen, dass diese Methode vom Anbieter nicht (mehr) empfohlen und möglicherweise eingestellt wird. Darüber hinaus ist das Abfragen im Vergleich zu DNS um den Faktor 2-3 langsamer.

Zugriff per DNS

Eine sehr effiziente Möglichkeit der Abfrage stellt das DNS durch Auflösung des Bezeichners {domain}.contacts.abuse.net dar; die Rückgabe der Adressen erfolgt in Form von TXT-Records.

Leider stellt das .NET-Framework jedoch nur einfache Aufgaben der Adress- und Namensauflösung per DNS-Klasse zur Verfügung. Da die Details der Kommunikation – zumindest in diesem Beitrag – nicht weiter vertieft werden sollen, greifen wir auf eine externe Laufzeitbibliothek zu, die wir mit NuGet bequem per Visual Studio beziehen können. Für das folgende Beispiel verwende ich ARSoft.Tools.Net, welche sich bereits in einigen meiner Entwicklungen im Produktiveinsatz bewährt hat und zudem auch relativ einfach zu verwenden ist.

Zugriff per DNS
010203040506070809101112
public static IEnumerable<string> GetAbuseContactList(params string[] domainList) {    foreach(string domain in domainList) {        DnsMessage response = DnsClient.Default.Resolve(            DomainName.Parse(domain + ".contacts.abuse.net"),            RecordType.Txt        );
foreach(TxtRecord record in response.AnswerRecords) { yield return record.TextData; } }}
Unabhängig davon, welche der beiden Methoden ihr verwendet, gestaltet sich die Verwendung sehr einfach:
Verwendung der Methode(n)
0102030405060708
  // ["abuse@coders-online.net"]IEnumerable<string> abuseContactList = GetAbuseContactList("coders-online.net");
// ["abuse@google.com", "abuse@microsoft.de"]abuseContactList = GetAbuseContactList("google.com", "microsoft.de");
// ["abuse@facebook.com", "spamreport@spamreport.facebook.com"]abuseContactList = GetAbuseContactList("facebook.com");
Auf eine angemessene Fehlerbehandlung habe ich wie üblich zur besseren Verdeutlichung des eigentlichen Anliegens verzichtet, sollte von euch bei der Verwendung aber nicht vernachlässigt werden.

Umgang mit Spam 👍 👎

Spam ist leider nach wie vor ein sehr großes Problem im Internet. Die genauen Arten und Hintergründe zum massenhaften Spam-Versand und insbesondere Ansätze zur grundlegenden Verbesserung der Protokolle sind sicherlich interessant und einen separaten Beitrag wert, für diesen Beitrag soll es jedoch darum gehen, wie man derzeit Spam vermeiden und was man mit bereits eingegangenem Spam anfangen kann, außer ihn zu löschen.

Versand von Spam vermeiden

Idealerweise gelangt Spam erst gar nicht in Umlauf; das spart unnötige Datenverarbeitung mit allen Konsequenzen und theoretisch jeglichen weiteren Aufwand. In der Praxis ist das nur begrenzt möglich, da die Protokolle sehr liberal entworfen wurden – was grundsätzlich lobenswert, bei Spam jedoch problematisch ist.

Inhaber von Postfächern

Was erst einmal selbstverständlich klingt, wird in der Praxis leider oftmals vernachlässigt: Sichere Passwörter tragen wesentlich dazu, dass eigene Benutzerkonten nicht als Absender für Spam fungieren. Wie üblich sollte das Passwort natürlich auch nur für genau diesen Zweck verwendet werden. Problematisch sind diese grundsätzlich "guten" Benutzerkonten insbesondere deshalb, weil sie meist aus den ordentlich konfigurierten Netzen größerer Anbieter stammen, die nicht einfach pauschal als "bekannte" Spam-Versender blockiert werden können.

Nicht zuletzt sollte auch sichergestellt sein, dass sich keine Schadprogramme auf dem eigenen Rechner befinden, welche beispielsweise eMails an Kontakte aus dem Adressbuch zu senden versuchen. Auch eigene Web-Anwendungen sollten immer auf dem aktuellsten Stand sein.

Betreiber von Mailservern

Ein ordentlich konfigurierter Mailserver, der nur authentifizierte Benutzer zulässt und insbesondere nicht als offenes Mail-Relay fungiert, ist selbstverständlich Grundvoraussetzung, um Spam bereits im Ansatz zu vermeiden. Die genaue Konfiguration hängt vom eingesetzten Dienst ab und würde den Rahmen dieses Beitrages sprengen. Üblicherweise gibt es dazu jedoch umfassende Leitfäden der Anbieter.

Ein weiterer Ansatz ist es, Spam an sich zu erkennen und von der weiteren Verarbeitung, insbesondere dem externen Versand, auszuschließen. So ist es beispielsweise möglich, den Umfang der Versandtätigkeit zu überwachen und ggf. auch einzuschränken. Ein durchschnittlicher Webhosting-Kunde wird beispielsweise eher selten mehrere tausend eMails in der Minute einreichen – hier können serverseitige Maßnahmen greifen, die derartige Auffälligkeiten erkennen. Möglicherweise ist es sinnvoll, die Anzahl der Nachrichten pro Zeiteinheit einzuschränken und nur nach vorheriger Rücksprache mit dem Kunden vorübergehend freizugeben.

Darüber hinaus ist nicht zu unterschätzen, dass die Zugangsdaten sehr vieler Benutzerkonten oftmals sehr unsicher gewählt werden und daher leicht zu "ermitteln" sind, bzw. von anderen Portalen kopiert werden können, sofern gleiche Zugangsdaten verwendet wurden. Es sollte daher überwacht werden, ob auffällige Zugriffe erfolgen – dieses Vorhaben kann beispielsweise durch Programme wie Fail2ban unterstützt werden. Auch Web-Anwendungen der Kunden, die oftmals nicht auf dem aktuellsten Stand sind, sind zu beachten.

Empfang von Spam vermeiden

Die meisten Anbieter leisten hier Vorarbeit, sodass der gröbste Spam gar nicht erst in dein Postfach gelangt, sondern bereits serverseitig abgewiesen wird. Alternativ wird teilweise auch nur eine Markierung eingesetzt, beispielsweise indem dem Betreff "[SPAM]" vorangestellt wird.

Inhaber von Postfächern

Du solltest deine eMail-Adresse(n) auf jeden Fall nicht überall verstreut angeben. Die meisten eMail-Programme bieten darüber hinaus standardmäßig oder aber zumindest über entsprechende Erweiterungen die Möglichkeit, Spam über bestimmte Kriterien zu erkennen. Die Erkennungsrate steigert sich bei den etwas besseren Programmen mit der Zeit, es können jedoch auch falsche Einstufungen (false positive) vorkommen.

Weniger der direkten Vermeidung, als vielmehr der Aufklärung dienlich ist der Ansatz, für jeden Dienst, bei dem du deine eMail-Adresse angeben sollst, eine individuelle und nicht erratbare Adresse zu erzeugen, die du nur dort verwendest (jedoch durchaus in einem Postfach mit anderen zusammen sammeln kannst). So kannst du feststellen, aus welcher Richtung du Spam erhältst und mit dem Anbieter Rücksprache halten, wie deine nur dort verwendete Adresse, die nur ihm bekannt sein sollte und nicht öffentlich einsehbar ist, Spam erhalten konnte. Möglicherweise wurde in einem solchen Fall unberechtigt auf die Daten(-bank) zugegriffen. Indirekt lässt sich mit diesem Ansatz Spam vermeiden, indem die fragliche Adresse schlicht gelöscht und ggf. eine neue erzeugt wird.

Betreiber von Mailservern

Es besteht grundsätzlich die Möglichkeit, einzelnen IP-Adressen oder sogar ganzen Adressbereichen die Verbindung zu verweigern. Darüber hinaus können eingehende Nachrichten über externe Programme wie SpamAssassin oder auch über bereits im Mailserver implementierte Funktionalität auf Spam geprüft werden.

Eine weitergehende Option ist das Einbinden von DNS-basierten Blacklisten, wobei die IP-Adresse eingehender Verbindungen gegen entsprechende Dienste geprüft und darauf basierend entschieden wird, ob die Nachricht angenommen wird. Die Anbieter dieser Dienste sammeln dazu auffällige Adressen in ihren Datenbanken. Bekannte Anbieter, die ich auch selbst auf meinem Server einsetze, sind beispielsweise die Folgenden:

Bitte informiert euch jedoch – insbesondere bei geplantem kommerziellen Einsatz – über die genauen Nutzungsbedingungen. Wie ihr die entsprechenden Dienste automatisiert mit C# ansprechen könnt, habe ich bereits in einem separaten Beitrag beschrieben.

Zuletzt sei noch auf die Möglichkeit des Greylistings hingewiesen, wobei eingehende eMails bei unbekannten Absendern zuerst abgewiesen werden. Hierbei wird ausgenutzt, dass korrekt konfigurierte Mailserver die Zustellung nach einer gewissen Zeit nochmals versuchen – Spammer vermeiden diesen Aufwand oftmals. Der Erfolg mit dieser Methode kann durchaus beachtlich sein, sorgt jedoch leider auch dafür, dass "dringende" eMails teilweise nur stark verzögert eingehen, was natürlich lästig sein kann.

Spam behandeln

Ist trotz aller Maßnahmen eine Spam-Nachricht im eigenen Postfach gelandet, so sollte man selbstverständlich keinesfalls irgendwelche Links anklicken (auch keine angeblichen "abmelden"-Links), Dateianhänge öffnen oder dem (angeblichen) Absender antworten. Bevor die Nachricht jedoch gelöscht wird, kann man durchaus noch sinnvolle Sachen damit anstellen.

Den Betreibern der verantwortlichen Server kann man eine Information zukommen lassen, dass man Spam erhalten hat. Dies ermöglicht dem Betreiber des Mailservers, der die Nachricht verschickt bzw. weitergeleitet hat, seinen Kunden darauf hinzuweisen oder ggf. auch zu sperren. Betreiber von Servern, auf die durch Links in den Spam-Nachrichten verwiesen wird, können u. U. auch interessiert sein, da nicht selten Sicherheitslücken auf legitimen Webseiten missbraucht werden, um beispielsweise Schadcode zu verbreiten. Größere Unternehmen reagieren nicht selten auch mit ihrer Rechtsabteilung, wenn beispielsweise (Ruf-)Schädigung durch Phishing droht, was dem Ganzen nochmals etwas mehr Nachdruck verleiht.

Die meisten direkt sichtbaren Domain-Angaben bei Spam-Nachrichten sind jedoch gefälscht, d. h. eine einfache Whois-Abfrage ist hier meist nicht zielführend. Vielmehr muss der eigentliche Server ausfindig gemacht (→ Untersuchung der eMail-Kopfzeilen) und über die zuständige Regional Internet Registry der passende Ansprechpartner ermittelt werden.

Leider ist es jedoch nicht ganz trivial, die richtigen Adressaten herauszufinden und für Laien nahezu unmöglich. Hier kann es eher passieren, dass man die Falschen "beschuldigt" und diese entsprechende Meldungen ab einem gewissen Ausmaß schlicht ignorieren. Hier helfen jedoch Anbieter weiter, die sich darauf spezialisiert haben:

  • abuse.net
    Dieser Dienst ermittelt zu einer Domain den Kontakt für Missbrauchsfälle, jedoch muss man dazu die "verantwortliche" Domain bereits kennen. Wie man diesen Dienst automatisiert (mit C#) ansprechen kann, erkläre ich in einem separaten Beitrag.
  • SpamCop
    Dieser Dienst nimmt die meiste Arbeit ab und ermittelt bei Eingabe einer vollständigen Spam-Nachricht (inkl. Kopfzeilen) die passenden Empfänger. Selbstverständlich empfiehlt sich jedoch eine Kontrolle, da in bestimmten Konstellationen die Automatismen unzureichend sind. An eine spezielle Adresse können Spam-Nachrichten auch direkt weitergeleitet werden.

Selbstverständlich ist das keine Garantie dafür, dass sich der Anbieter auch ernsthaft darum kümmert – hier gibt es leider auch uninteressierte Zeitgenossen. Ich melde jedoch generell alle Spam-Nachrichten und habe damit durchaus überwiegend gute Erfahrungen gemacht und erhalte hin und wieder auch persönliche Antworten.

DNS-Cache unter Windows und mit C# leeren 👍 👎

Um den DNS-Zwischenspeicher unter Windows zu leeren, gibt es den bekannten Befehl ipconfig /flushdns.

Prinzipiell wäre es zwar möglich, das Programm ipconfig mit dem Argument /flushdns über die Process-Klasse per C# aufzurufen, jedoch ist dies nicht ganz unproblematisch, da die Ausführung längere Zeit dauern kann.

Alternativ hilft uns hier – wieder einmal – die Windows-API in Kombination mit dem DllImport-Attribut:
(Hilfs-)Methode deklarieren und verwenden
01020304050607
public static class DnsUtility {    [DllImport("dnsapi", EntryPoint = "DnsFlushResolverCache")]    public static extern void FlushCache();}
// DNS-Cache leerenDnsUtility.FlushCache();
Dies ist insbesondere in Verbindung mit der Dns-Klasse nützlich, um aktuelle Daten zu erhalten. Natürlich gibt es einen solchen Zwischenspeicher aber nicht grundlos, d. h. es ist nur äußerst selten ratsam, diesen immer wieder vor einer Namensauflösung zu leeren – Performanzdifferenzen im Rahmen einer Größenordnung sind hier üblich. Im Rahmen des Debuggings oder für besonders kritische Prozesse kann das Vorgehen jedoch durchaus sinnvoll sein.

Bezeichner eines Members mit C# ermitteln 👍 👎

Bei C# kommt man beispielsweise bei der Fehlerbehandlung (z. B. per ArgumentException und abgeleiteten Klassen), Logging (im Sinne von "Methode MethodName betreten/verlassen") oder auch beim Routing im Rahmen des ASP.NET MVC-Frameworks in die Notwendigkeit, Programmbezeichner als Zeichenketten anzugeben.

Etwas ärgerlich ist hier jedoch immer, was man bei grundsätzlich statisch typisierten Sprachen wie C# für gewöhnlich vermeiden möchte: Derartige Zeichenketten sind literal hinterlegt und dementsprechend einer Refaktorierung nicht ohne Weiteres zugänglich. Dieses Problem löst nun das relativ neue Konstrukt nameof, indem es die (einfachen) Bezeichner von Variablen, Typen und Membern als Zeichenkette liefert:
Beispiel-Klasse definieren und Member-Bezeichner ermitteln
01020304050607080910111213141516171819202122
public class Person {    public string FirstName {        get;        set;    }
public string LastName { get; set; }

public void Marry(Person person) { /* … */ }}

Debug.WriteLine(nameof(Person)); // "Person"Debug.WriteLine(nameof(Person.FirstName)); // "FirstName"Debug.WriteLine(nameof(Person.LastName)); // "LastName"Debug.WriteLine(nameof(Person.Marry)); // "Marry"
Praktisch ist nun, dass bei der Umbenennung einer Eigenschaft oder Methode, sich dieser Vorgang auch auf die entsprechende Verwendung innerhalb von nameof auswirkt und somit für Konsistenz sorgt.

Ein weiterer theoretischer Anwendungsfall ergibt sich im Rahmen einer INotifyPropertyChanged-Implementierung, jedoch lässt sich dieses Problem auch ganz ohne manuelle Angabe per CallerMemberName-Attribut lösen, wie ich in einem früheren Beitrag bereits beschrieben habe.

Anwendungssymbol mit C# extrahieren 👍 👎

Desktop-Anwendungen (*.exe) enthalten häufig ein Programmsymbol, welches insbesondere im Windows Explorer und auf der Taskleiste angezeigt wird. Das Ermitteln dieses Anwendungssymbols, beispielsweise für eigene Auflistungen, ist sehr einfach über Icon.ExtractAssociatedIcon() realisierbar:
Anwendungssymbol extrahieren
0102030405060708091011
using(Icon icon = Icon.ExtractAssociatedIcon("devenv.exe")) {      // Programmsymbol als *.ico-Datei speichern    using(FileStream fileStream = File.OpenWrite("devenv.ico")) {        icon.Save(fileStream);    }
// Programmsymbol als *.png-Datei speichern using(Bitmap bitmap = icon.ToBitmap()) { bitmap.Save("devenv.png", ImageFormat.Png); }}
Bitte beachtet wie üblich in solchen Fällen, dass die Verwendung der Grafik rechtlich eingeschränkt sein kann.