Datenhaufen zu IT und Elektronik.

Schlagwort: E-Mail (Seite 1 von 2)

GPT in Rspamd aktivieren: so nutze ich das LLM-Signal im Score

Setup: FreeBSD 14.3, Rspamd 3.12.1, Postfix + Dovecot. Ich lasse bei kniffligen Mails zusätzlich ein LLM draufschauen. Wichtig: GPT ist bei mir nur ein weiterer Sensor im ganz normalen Rspamd-Scoring — keine Allzweckwaffe und kein „hartes Urteil“.

Voraussetzungen

  • Rspamd inkl. GPT-Plugin (ab ~3.12.x im Paket; konfiguriert wird in local.d/gpt.conf).
  • API-Zugang (OpenAI-kompatibel oder eigener Endpunkt).
  • Grundverständnis zu Rspamd-Metrics/Actions (Reject/Add-Header/Greylist).

OpenAI API Key erstellen: Melde dich auf der Developer-Plattform an, öffne die Seite API Keys und klicke auf Create new secret key. Lege bei Bedarf Berechtigungen fest oder arbeite mit projektbasierten Keys. Kopiere den Key einmalig und bewahre ihn sicher (root-only) auf – bitte nicht teilen. Nutzung/Kosten siehst du im Usage-Dashboard.

Mein gpt.conf

Ich halte die Konfiguration bewusst nüchtern — genug, um robuste Labels zu bekommen, aber ohne Schnickschnack:

# local.d/gpt.conf (Auszug)
enabled = true;
type = "openai";
model = "gpt-4o-mini";
api_key = "GEHEIMER-KEY";

model_parameters {
  gpt-4o-mini {
    max_tokens = 160;
    temperature = 0.0;
  }
}

timeout = 10s;
allow_ham = true;
allow_passthrough = false;
json = false;
reason_header = "X-GPT-Reason";

input = "text";
min_words = 1;
max_size = 256k;

symbols_to_except {
  RCVD_IN_DNSWL_MED = -0.1;
  RCVD_IN_DNSWL_HI  = -0.1;
  DWL_DNSWL_MED     = -0.1;
  WHITELIST_RECP_ADDR = -0.1;
  GREYLIST = 0; GREYLIST_CHECK = 0; GREYLIST_SAVE = 0;
  RCPT_IN_SPAMTRAP = 0; SPAMTRAP = 0; SPAMTRAP_ADDR = 0;
  RCVD_VIA_SMTP_AUTH = 0; LOCAL_CLIENT = 0; FROM_LOCAL = 0;
}

Was bedeutet das?!

  • model = gpt-4o-mini: flott & günstig, deterministisch per temperature = 0.0.
  • allow_ham = true: GPT darf „HAM“ melden (kleines, positives Signal).
  • allow_passthrough = false: Bei Fehlern (Timeout/API down) keine stillen Freifahrten.
  • reason_header = "X-GPT-Reason": Kurzbegründung landet im Header (s.u. Datenschutz).
  • symbols_to_except: Offensichtliche interne Fälle werden neutralisiert, damit GPT nicht in klaren Situationen wirkt.
  • Limits: min_words = 1, max_size = 256k, timeout = 10s.

Metric/Scoring: drei GPT-Symbole

symbols {
  GPT_SPAM       { weight = 9.0;  group = "gpt"; description = "GPT: classified as SPAM"; }
  GPT_SUSPICIOUS { weight = 4.5;  group = "gpt"; description = "GPT: classified as SUSPICIOUS"; }
  GPT_HAM        { weight = -0.5; group = "gpt"; one_shot = true; description = "GPT: classified as HAM"; }
}

GPT wirkt wie ein starker, aber nicht absoluter Faktor.
SPAM (9.0): kräftiger Zuschlag.
SUSPICIOUS (4.5): sanfter Schubs Richtung Greylist/Review.
HAM (-0.5): kleine Entlastung, einmalig pro Mail.

Warum diese Gewichte?
Die Zahlen habe ich bewusst so gewählt, dass das GPT-Signal stark, aber nie absolut ist. Rspamd summiert Scores, GPT ist also nur ein Faktor:

  • GPT_SPAM = 9.0: genug, um bei Kombination mit klassischen Checks (Bayes, RBL, DMARC) die Add-Header-Schwelle sicher zu reißen, aber unterhalb von reject allein.
  • GPT_SUSPICIOUS = 4.5: halber Wert, schiebt Grauzonen in Richtung Greylist/Review, ohne sofortige Eskalation.
  • GPT_HAM = -0.5: nur eine kleine Entlastung (one_shot). So verhindert man, dass GPT-HAM mehrere Punkte abzieht und Spams „rettet“.

Wie wird die GPT-Gewichtung berechnet?
In den Logs/WebUI taucht das oft so auf: GPT_SPAM(2.10)[0.85]. Das bedeutet:

  • [0.85] = Rohwert von GPT, z. B. 85 % Wahrscheinlichkeit für Spam.
  • weight aus der Metric (z. B. 9.0 für GPT_SPAM).
  • Grundformel: Rohwert × weight → ergibt den Beitrag zum Gesamtscore.
  • Hinweis: Je nach Rspamd-Version kann der im Header gezeigte Wert zusätzlich skaliert sein (z. B. falls das Modell nur ein „softes“ Signal liefert). Deshalb sieht man in der Praxis häufig 2–8 Punkte statt des Maximalgewichts.

Actions/Schwellen

actions {
  greylist = 4;
  add_header = 6;
  reject = 15;
}

SUSPICIOUS (4.5) kippt oft in Greylist. SPAM (9.0) bringt fast immer Add-Header, Reject nur zusammen mit weiteren harten Befunden. Klassische Checks (SPF/DKIM/DMARC, RBL, Bayes) bleiben führend, GPT ergänzt nur.

Tuning
Zu bissig? Gewicht etwas senken.
Zu lasch? Gewicht erhöhen.
Zu optimistisch bei HAM? Gewicht kleiner machen oder 0 setzen.
Header mit X-GPT-Reason liefert Nachvollziehbarkeit, kann bei Bedarf wieder entfernt werden.

Praxis
– Symbole erscheinen im WebUI und Logfiles.
X-GPT-Reason erklärt im Header die Bewertung.
– Latenz/Kosten: gpt-4o-mini mit 160 Tokens und 10 s Timeout ist performant und günstig.

Jetzt schauen wir uns mal die Mailheader eines echten Beispiels an und wie GPT dort gegriffen hat:

X-Spamd-Result: default: False [8.59 / 15.00];
        VIOLATED_DIRECT_SPF(3.50)[];
        GPT_SPAM(2.10)[0.85];
        MISSING_MIMEOLE(2.00)[];
        CTYPE_MIXED_BOGUS(1.00)[];
        MID_RHS_NOT_FQDN(0.50)[];
        DMARC_POLICY_ALLOW_WITH_FAILURES(-0.50)[];
        MIME_HTML_ONLY(0.20)[];
        R_DKIM_ALLOW(-0.20)[thejewelbox.dd:s=1759374209.thejewelbox];
        ...

Erklärung:

  • X-Spamd-Result: [8.59 / 15.00] – Gesamtscore 8.59, Reject-Schwelle bei 15. Hier also kein Reject, sondern nur Add-Header.
  • GPT_SPAM(2.10)[0.85] – GPT meldet Spam mit 85 % Sicherheit ([0.85]). Daraus errechnet Rspamd den Beitrag ((…)), der in den Gesamtscore einfließt.
  • Die klassischen Checks wie VIOLATED_DIRECT_SPF(3.50) oder MISSING_MIMEOLE(2.00) haben ebenfalls beigetragen – GPT ist also nur ein Faktor im Gesamtbild.

Zusätzlich schreibt das GPT-Modul auf Wunsch auch eine kurze Begründung in den Mailheader:

X-GPT-Reason: This email is likely spam due to the urgency created around an unpaid invoice and the mismatch between the sender's domain and the company name.

Erklärung:

  • X-GPT-Reason – eigener Header, den du in gpt.conf mit reason_header = "X-GPT-Reason" aktivierst.
  • Der Text stammt direkt aus dem Modell und begründet die Einstufung (hier: Dringlichkeit „unpaid invoice“ + Domain/Company-Mismatch).
  • Nützlich für Analyse/Transparenz; kann auf MTA/MDA-Ebene wieder entfernt werden, wenn du ihn nicht bis zum Postfach durchreichen willst.

Ein Hinweis zum Datenschutz (gesamt)
Mit GPT-Integration gehen Mailinhalte an einen externen Dienst (z. B. OpenAI). Das kann datenschutzrechtlich relevant sein. Wer sensible oder personenbezogene Daten verarbeitet, sollte vorher prüfen, ob die Nutzung zulässig ist – oder alternativ ein selbst gehostetes, OpenAI-kompatibles Modell nutzen (z. B. Ollama). Den Reason-Header kannst du, falls nötig, serverseitig wieder entfernen.

Rspamd: Automatisches Spam/Ham-Lernen mit Dovecot und IMAPSieve

Bei jedem Spamfilter kann es vorkommen, dass Spam durchrutscht oder eine echte Nachricht fälschlicherweise als Spam eingestuft wird. Rspamd bietet über das Webinterface die Möglichkeit, trainiert zu werden. Hier kann man einfach den Quellcode jeder E-Mail kopieren und Rspamd mitteilen, ob es sich dabei um Spam (SPAM) oder um eine legitime Nachricht (HAM) handelt. Dieses Vorgehen ist jedoch ungeeignet, um den Spamfilter effektiv zu trainieren.

Dovecot and RSPAMD Logo

Wünschenswert wäre folgende Lösung: Immer wenn ein Benutzer eine E-Mail in den Ordner „Junk“ verschiebt, sollte diese E-Mail automatisch von Rspamd als Spam gelernt werden. Zusätzlich sollte jede E-Mail, die der Benutzer aus dem „Junk“-Ordner herausholt, als Ham gelernt werden.

Genau dieses Szenario möchte ich hier kurz beschreiben. Das Hostsystem ist ein FreeBSD; Linux-User müssen daher bei den Pfaden wie /usr/local aufpassen! Ebenfalls lauscht mein Rspamd-Worker nicht auf einem Unix-Socket, sondern auf der IP 127.0.0.3, da er in einer Jail-Umgebung läuft.

Beginnen wir mit der Konfiguration für Dovecot.

20-imap.conf:

protocol imap {
  mail_plugins = $mail_plugins sieve
}

90-plugin.conf:

plugin {
  sieve_plugins = sieve_imapsieve sieve_extprograms

  # From elsewhere to Spam folder or flag changed in Spam folder
  imapsieve_mailbox1_name = Junk
  imapsieve_mailbox1_causes = COPY FLAG
  imapsieve_mailbox1_before = file:/usr/local/etc/dovecot/sieve/report-spam.sieve

  # From Spam folder to elsewhere
  imapsieve_mailbox2_name = *
  imapsieve_mailbox2_from = Junk
  imapsieve_mailbox2_causes = COPY
  imapsieve_mailbox2_before = file:/usr/local/etc/dovecot/sieve/report-ham.sieve

  sieve_pipe_bin_dir = /usr/local/libexec/dovecot

  sieve_global_extensions = +vnd.dovecot.pipe
}

/usr/local/etc/dovecot/sieve/report-spam.sieve:

require ["vnd.dovecot.pipe", "copy", "imapsieve", "environment", "imap4flags"];

if environment :is "imap.cause" "COPY" {
    pipe :copy "sa-learn-spam.sh";
}

# Catch replied or forwarded spam
elsif anyof (allof (hasflag "\\Answered",
                    environment :contains "imap.changedflags" "\\Answered"),
             allof (hasflag "$Forwarded",
                    environment :contains "imap.changedflags" "$Forwarded")) {
    pipe :copy "sa-learn-spam.sh";
}

/usr/local/etc/dovecot/sieve/report-ham.sieve:

require ["vnd.dovecot.pipe", "copy", "imapsieve", "environment", "variables"];

if environment :matches "imap.mailbox" "*" {
  set "mailbox" "${1}";
}

if string "${mailbox}" [ "Trash", "train_ham", "train_prob", "train_spam" ] {
  stop;
}

pipe :copy "sa-learn-ham.sh";

Natürlich nicht vergessen, die beiden neuen Sieve-Skripte für Sieve zu kompilieren:

# sievec /usr/local/etc/dovecot/sieve/report-spam.sieve
# sievec /usr/local/etc/dovecot/sieve/report-ham.sieve

Es fehlen nur noch die beiden Shell-Skripte, um die Mails an Rspamd weiterleiten zu können.

/usr/local/libexec/dovecot/sa-learn-spam.sh:

#!/bin/sh
exec /usr/local/bin/rspamc -h 127.0.0.3:11334 learn_spam

/usr/local/libexec/dovecot/sa-learn-ham.sh:

#!/bin/sh
exec /usr/local/bin/rspamc -h 127.0.0.3:11334 learn_ham

Beide müssen ausführbar sein:

# chmod +x /usr/local/libexec/dovecot/sa-learn-spam.sh /usr/local/libexec/dovecot/sa-learn-ham.sh

Wenn ich nun eine E-Mail in den Ordner „Junk“ verschiebe, lernt Rspamd diese automatisch als Spam:

2020-05-04 11:21:02 #92071(controller) <b91225>; csession; rspamd_controller_check_password: allow unauthorized connection from a trusted IP 127.0.0.3
2020-05-04 11:21:02 #92071(controller) <b91225>; csession; rspamd_message_parse: loaded message; id: <FNgLHBeARhiVYgEegF_-Pw@ismtpd0002p1lon1.sendgrid.net>; queue-id: <undef>; size: 49053; checksum: <f5e2fc59515e1da33d532c6f03f6f6f0>
2020-05-04 11:21:02 #92071(controller) <b91225>; csession; rspamd_mime_part_detect_language: detected part language: de
2020-05-04 11:21:02 #92071(controller) <b91225>; csession; rspamd_mime_part_detect_language: detected part language: de
2020-05-04 11:21:02 #92071(controller) <b91225>; csession; rspamd_controller_learn_fin_task: <127.0.0.3> learned message as spam: FNgLHBeARhiVYgEegF_-Pw@ismtpd0002p1lon1.sendgrid.net

Verschiebe ich eine E-Mail aus dem Ordner „Junk“ heraus, wird sie, wie gewünscht, als Ham gelernt:

2020-05-04 11:20:51 #92071(controller) <a7fe42>; csession; rspamd_controller_check_password: allow unauthorized connection from a trusted IP 127.0.0.3
2020-05-04 11:20:51 #92071(controller) <a7fe42>; csession; rspamd_message_parse: loaded message; id: <FNgLHBeARhiVYgEegF_-Pw@ismtpd0002p1lon1.sendgrid.net>; queue-id: <undef>; size: 49053; checksum: <f5e2fc59515e1da33d532c6f03f6f6f0>
2020-05-04 11:20:51 #92071(controller) <a7fe42>; csession; rspamd_mime_part_detect_language: detected part language: de
2020-05-04 11:20:51 #92071(controller) <a7fe42>; csession; rspamd_mime_part_detect_language: detected part language: de
2020-05-04 11:20:51 #92071(controller) <a7fe42>; csession; rspamd_controller_learn_fin_task: <127.0.0.3> learned message as ham: FNgLHBeARhiVYgEegF_-Pw@ismtpd0002p1lon1.sendgrid.net

Fragen? Einfach fragen!

Ach, und was man nicht mehr verwenden sollte: das Antispam-Plugin – das ist „tot“.

Automatische E-Mail-Archivierung mit Dovecot IMAP einrichten

Um etwas mehr Ordnung in meinem IMAP Postfach zu halten nutzen ich ein kleines Python Skript cleanup-maildir https://www.freshports.org/mail/cleanup-maildir/. Dieses Skript läuft jede Nacht und sortiert automatisch alle E-Mails die älter sind als 365 Tage aus meinem Posteingang (inbox) sowie meinen Gesendeten E-Mails ins Archive. Dabei sortiert es die Mails automatisch in Unterordner mit dem Jahres und Monatsnamen, damit ich die E-Mails schneller finden kann.

Zum Beginn lief es nur als cronjob auf meinem Postfach, inzwischen sammelt es sich die Benutzer, den MailBox Pfad sowie die Option ob es laufen soll oder nicht (autoarchive=0|1) aus dem LDAP Server.

Den grundlegenden Aufruf des Skriptes möchte ich kurz mit euch teilen!

sudo -u vmboxuser cleanup-maildir --age=365 --archive-folder='Archive.Inbox' --maildir-root='/var/mail/vhosts/kernel-error.com/kernel-error' archive ''
sudo -u vmboxuser cleanup-maildir --age=365 --archive-folder='Archive.Sent' --maildir-root='/var/mail/vhosts/kernel-error.com/kernel-error' archive 'Sent/'

sudo -u vmboxuser lässt den Befehl als der Nutzer laufen, welcher bei mir übergreifen Zugriff auf die Postfächer hat.
–age=365 sagt, dass nur E-Mails älter 365 Tage angefasst werden sollen.
–archive-folder=’Archive.Inbox/Sent‘ gibt die Zielordner im Postfach an.
–maildir-root='[…]‘ das Postfach (Domain und Postfachname kommen normalerweise als Variable aus dem LDAP).
archive sagt dem Skript, dass archiviert werden soll. Man könnte auch löschen oder ähnliches.
ist der Default also die Inbox
‚Sent/‘ sind die gesendeten E-Mail.

 Die entstehende Ordnerstruktur im Postfach ist dann:

Screenshot der IMAP Archive Ordnerstruktur.

Tjo… Läuft seit Jahren sehr gut und räumt die Postfächer automatisch auf.

Outlook Autodiscover für IMAP und SMTP konfigurieren

Vor einigen Jahren habe ich bereits etwas zu Microsoft Outlook und dessen Autodiscover geschrieben. Microsoft Office Outlook Autodiscover

Ich setze es noch immer in recht ähnlicher Form ein und möchte den aktuellen Stand kurz beschreiben.

Primär habe ich eine Autodiscoverdomain https://autodiscover.kernel-error.de hinter dieser steht ein nginx und er liefert unter diesem Pfad https://autodiscover.kernel-error.de/Autodiscover/Autodiscover.xml die Konfigurationsinformationen für verschiedene Maildomains für smtps und imaps aus.

Die Konfiguration vom nginx ist recht überschaubar. Klar, https und der spannende Teil der Konfiguration ist folgender:

        location ~ /(?:a|A)utodiscover/(?:a|A)utodiscover.xml {
        root /usr/local/www/autodiscover.kernel-error.de;
        try_files /autodiscover/autodiscover.php =404;
        fastcgi_split_path_info ^(.+\.php)(/.+)$;
        fastcgi_pass unix:/var/run/php-fpm.sock;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $request_filename;
        include fastcgi_params;
        fastcgi_cache MYAPP;
        fastcgi_cache_valid 200 60m;
    }

Wie man gut sehen kann wird einfach jede Anfrage nach /autodiscover/autodiscover.xml (egal ob am Anfang groß oder klein geschrieben), im Hintergrund weitergeleitet an das php file autodisvocer.php:

<?php

/********************************
 * Autodiscover responder
 ********************************
 * This PHP script is intended to respond to any request to http(s)://mydomain.com/autodiscover/autodiscover.xml.
 * If configured properly, it will send a spec-complient autodiscover XML response, pointing mail clients to the
 * appropriate mail services.
 * If you use MAPI or ActiveSync, stick with the Autodiscover service your mail server provides for you. But if 
 * you use POP/IMAP servers, this will provide autoconfiguration to Outlook, Apple Mail and mobile devices.
 *
 * To work properly, you'll need to set the service (sub)domains below in the settings section to the correct 
 * domain names, adjust ports and SSL.
 */

//get raw POST data so we can extract the email address
$request = file_get_contents("php://input");

// optional debug log
# file_put_contents( 'request.log', $request, FILE_APPEND );

// retrieve email address from client request
preg_match( "/\<EMailAddress\>(.*?)\<\/EMailAddress\>/", $request, $email );

// check for invalid mail, to prevent XSS
if (filter_var($email[1], FILTER_VALIDATE_EMAIL) === false) {
	throw new Exception('Invalid E-Mail provided');
}

/**************************************
 *   Port and server settings below   *
 **************************************/

// IMAP settings
$imapServer = 'imap.kernel-error.de'; // imap.example.com
$imapPort   = 993;
$imapSSL    = true;

// SMTP settings
$smtpServer = 'smtp.kernel-error.de'; // smtp.example.com
$smtpPort   = 465;
$smtpSSL    = true;

//set Content-Type
header( 'Content-Type: application/xml' );
?>
<?php echo '<?xml version="1.0" encoding="utf-8" ?>'; ?>
<Autodiscover xmlns="http://schemas.microsoft.com/exchange/autodiscover/responseschema/2006" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >
	<Response xmlns="http://schemas.microsoft.com/exchange/autodiscover/outlook/responseschema/2006a">
		<Account>
			<AccountType>email</AccountType>
			<Action>settings</Action>
			<Protocol>
				<Type>IMAP</Type>
				<Server><?php echo $imapServer; ?></Server>
				<Port><?php echo $imapPort; ?></Port>
				<DomainRequired>off</DomainRequired>
				<LoginName><?php echo $email[1]; ?></LoginName>
				<SPA>off</SPA>
				<SSL><?php echo $imapSSL ? 'on' : 'off'; ?></SSL>
				<AuthRequired>on</AuthRequired>
			</Protocol>
			<Protocol>
				<Type>SMTP</Type>
				<Server><?php echo $smtpServer; ?></Server>
				<Port><?php echo $smtpPort; ?></Port>
				<DomainRequired>off</DomainRequired>
				<AuthRequired>on</AuthRequired>
				<LoginName><?php echo $email[1]; ?></LoginName>
				<SPA>off</SPA>
				<SSL><?php echo $imapSSL ? 'on' : 'off'; ?></SSL>
				<AuthRequired>on</AuthRequired>
				<SMTPLast>off</SMTPLast>
				<UsePOPAuth>off</UsePOPAuth>
			</Protocol>
		</Account>
	</Response>
</Autodiscover>

Das kleine php script macht auch nicht viel mehr als die im Post übermittelte E-Mail Adresse in eine Variable zu schieben, zu prüfen ob es wirklich eine E-Mail Adresse ist und dann am Ende einfach das fertige xml zurück zu liefern.

Besonders wichtig dabei ist:

<AuthRequired>on</AuthRequired>
<SMTPLast>off</SMTPLast>
<UsePOPAuth>off</UsePOPAuth>

Sonst darf man für den Postausgangsserver nämlich immer manuell den Haken setzen bei: „Gleiche Einstellungen wie für den Posteingangsserver verwenden“ Welches sicher einige Anwender vor einer nur schwer zu überwindenden Hürde stell.

Damit dieses nicht nur für E-Mail Adresse der Domain kernel-error.de funktioniert gibt es in den anderen DNS Zonen SRV RRs welche auf diese Autodiscoverdomain verweisen:

➜  ~ dig _autodiscover._tcp.kernel-error.com IN SRV +short
0 0 443 autodiscover.kernel-error.de.

Nun sorgt dieses bei Outlook für eine kleine Warnmeldung bei der Konfiguration, ob man diesem Verweis wirklich folgen möchte.

Screenshot vom Outlook Client beim Konto hinzufügen. Frage ob die Konfiguration der Servereinstellungen von einer Webseite zugelassen werden soll.

Dieses kommt nur einmalig und man könnte es zudem mit deinem Registierungsschlüssel unterbinden aber naja das sollte für jeden klickbar sein, oder?!?! Im Anschluss ist die Konfiguration vom E-Mail Client schon abgeschlossen.

Screenshot vom Outlook Client beim Konto hinzufügen. Vorgang wurde erfolgreich abgeschlossen.

Wie man sieht ist es sehr simpel und sollte von nahezu jedem erledigt werden können, der es schafft seine E-Mail Adresse und sein Kennwort nach dem Outlookstart einzugeben.

Postfix: Client-Initiated Renegotiation sicher deaktivieren

client-initiated renegotiation beim SMTPD Server kann für DDoS Angriffe ausgenutzt werden. Die einzelnen TLS/SSL Optionen lassen sich über die recht gleichnamige Option im Postfix ein und ausschalten. Gibt es noch keinen mappenden Namen kann die jeweilige Option auch ein/ausgeschaltet werden mit dem jeweiligen Hexwert. Genau Infos findet man hier: http://www.postfix.org/postconf.5.html#tls_ssl_options

If the value of the parameter is a hexadecimal long integer starting with "0x", the options corresponding to the bits specified in its value are enabled (see openssl/ssl.h and SSL_CTX_set_options(3))

Für ein Postfix  3.3 und einem OpenSSL ab Version 1.1.1 ist der passende Hexwert 0x40000000.

Die Option setzt man wie so oft in der main.cf:

root@smtp:/ # postconf  tls_ssl_options
tls_ssl_options = 0x40000000

Ab Postfix >=3.4 gibt es: NO_RENEGOTIATION

Fragen? Dann fragen 🙂

Postfix: E-Mail-Verschleierung gezielt einrichten

Um sich vor Angreifern zu schützen ist ein ganz gutes Mittel, dem Angreifer nicht direkt zu erzählen welche Software genau und in welcher Version man diese einsetzte. Bei Webservern ist dieses fast überall gängige Praxis, meist bekommt man nur noch das Produkt angezeigt. Oder wie bei einem Kollegen nur YOUR MUM. Warum ist das nun ggf. hilfreich? Ganz simples Beispiel. Man setzt einen verwundbaren Mailclient auf seinem Desktop ein, oder hat einen phpmailer (*würk*) in seiner Webseite eingebaut. Versendet man über diesen nun eine E-Mail schreibt er meist seinen eigenen Namen mit der eingesetzten Version in die E-Mail Header. Copy & Paste fertig für einen möglichen Angreifer, damit er die „Bugzilla Page“ nach den brauchbarsten Löchern durchwühlen kann. Dann muss er nur noch eine passende präparierte E-Mail schreiben und der Client wird leiden.

Ähnlich ist es mit den IP Adressen. Die IP Adresse des Clients landet ebenfalls in den Mail Headern. So hat der Angreifer schon mal eine Idee über die Netztopologie oder es gibt ihm ggf. eine Möglichkeit den Benutzer durch verschiedene Netze zu „tracken“.

Beides lässt sich über die smtp_header_checks etwas entschärfen. Über diesen Weg kann man per RegEx bestimmte Mail Header heraussuchen und löschen oder nach eigenem Ermessen ersetzten.

Hier der Eintrag für die main.cf:

root@smtp:/usr/local/etc/postfix # postconf smtp_header_checks
smtp_header_checks = pcre:/usr/local/etc/postfix/header_cleanup

Hier das Beispiel für die /usr/local/etc/postfix/header_cleanup:

/^(Received: from)[^\n]*(.*)/ REPLACE $1 ::88 (YOUR MOM [::88])$2
/^X-Originating-IP/ IGNORE
/^User-Agent*(.*)/ REPLACE User-Agent: YOUR MOMS MAILER
/^X-Mailer*(.*)/ REPLACE X-Mailer: YOUR MOMS MAILER

Im Ergebnis sieht es dann wie folgt aus:

[...]
Received: from ::88 (YOUR MOM [::88])
	(using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits))
	(No client certificate requested)
	by smtp.kernel-error.de (Postfix) with ESMTPSA id 7458E7B802
	for <wurst@example.com>; Wed, 27 Mar 2019 21:44:10 +0100 (CET)
[...]
X-Mailer: YOUR MOMS MAILER
[...]

Ganz wichtig ist natürlich die Frage ob dabei Signaturen gebrochen werden; das werden sie nicht. Auch DKIM usw. nicht.

Dann mal viel Spaß!

Die Akte „IGNORANT“

Ein Lehrstück über Mail, Macht, und die merkwürdige Waffe namens DNS

Es begann nicht mit Explosionen. Es begann mit einem Bounce.

Ein einziger, stiller Bounce – so leise, dass er in der täglichen Flut aus Logzeilen untergehen wollte. Ein 550, trocken wie Kreide:

550 5.1.1 <abuse@domain.tld>: Recipient address rejected: User unknown

Der Absender war ein kleiner Provider, irgendein abgegriffenes Abuse-Postfach, das seit Tagen versucht hatte, jemanden zu erreichen. Die Mail selbst war banal: „Ihre Domain wird für Spam missbraucht, bitte prüfen Sie Ihre Systeme.“ Keine Drohung, kein Drama. Nur ein Handgriff im Maschinenraum: „Schraube locker – bitte nachziehen.“

Noir-style cyber investigation scene with a shadowy analyst at a desk, green terminal showing ‘RFC-Ignorant.org blacklist – no abuse@ / no postmaster@’, and a case board labeled ‘Missing Contacts’ in the background.

Nur war da niemand, der die Schraube nachzog.

Und genau da, in diesem winzigen, fast lächerlichen 550, begann die Operation.

1) Der Mann im Schatten der RFCs

In den frühen 2000ern war das Netz gleichzeitig größer und kleiner. Größer, weil plötzlich jeder einen Mailserver betreiben konnte. Kleiner, weil die Leute, die es wirklich taten, sich kannten – über Mailinglisten, Konferenzen, und die ewigen Schlachten um Anti-Spam-Policy.

Unser Protagonist – nennen wir ihn M. – war keiner von den Lauten. Kein Held, kein Prediger. Er war ein Admin mit dem seltenen Talent, die Welt nicht moralisch zu deuten, sondern operativ.

Seine Welt bestand aus:

  • maillog bei 3 Uhr morgens
  • MRTG-Graphen, die wie EKGs von sterbenden Routern aussahen
  • dig, tcpdump, grep
  • und den RFCs – nicht als Religion, sondern als Werkzeugkiste

M. hatte diese eine fixe Idee: Wenn das Netz schon aus freiwilligen Regeln besteht, dann sind Kontaktadressen die Nieten im Stahl. Ohne Nieten fällt der Kran auseinander. Und „Kontaktadresse“ hieß in diesem Bereich: postmaster@ und abuse@.

  • postmaster@ – der Notausgang für SMTP-Probleme, traditionell Pflicht in der Mailwelt
  • abuse@ – die Stelle, an die man Missbrauch meldet, wenn’s brennt

Und jetzt kam der Haken: Du konntest die beste Abuse-Meldung der Welt schreiben – wenn die Gegenseite „User unknown“ sagt, bleibt der Brand ein Waldbrand.

M. nannte das nicht „Ignoranz“ aus Spaß. Er meinte es wörtlich: Wer nicht erreichbar ist, ist für den Betrieb nicht existent.

2) Die erste Liste – wie man Druck baut, ohne eine Waffe anzufassen

Eines Abends – der Kaffee war kalt, der Pager lauter als nötig – schrieb M. eine kleine Zone-Datei. Kein Kunstwerk. Ein schlichtes Stück Text, ein paar A-Records, eine Reihe von Domains, die auf eine IP zeigten.

So funktionieren DNSBLs: Du drehst die Frage um.

Statt „Ist diese Domain gut?“ fragst du:

„Wenn ich reversed-stuff.blacklist.example nachschlage – bekomme ich eine Antwort?“

Bekommst du eine Antwort, ist es ein Treffer. Kein Treffer, keine Antwort.

DNS als binärer Schalter. Brutal. Elegant. Gefährlich.

M. wusste, was er da baute: eine Art Signalfeuer für Mailadmins. Keine Zensurbehörde – eher ein „da stimmt was nicht“-Indicator, der automatisch verwertbar war.

Das Ziel war simpel formuliert:

  • Domain betreibt MX (oder nutzt Mail)
  • aber postmaster@domain und/oder abuse@domain sind nicht erreichbar
  • also: Eintrag in „IGNORANT“
  • wer die Liste nutzt, kann Mails von dort markieren oder härter behandeln

Nicht blocken war die „sanfte“ Variante. Viele taten’s trotzdem, weil Admins Admins sind: Wenn es eine Kante gibt, wird sie genutzt.

M. sagte dazu nur: „Ich liefere Daten. Policy ist euer Problem.“
Und damit hatte er recht – und auch wieder nicht. Daten sind nie nur Daten, wenn sie in SMTP-Pipelines landen.

3) Der erste Feldtest – RCPT TO als Lügendetektor

Die Methode war bestechend, weil sie so alt war wie SMTP selbst: Frag den Server direkt.

Ein Testlauf sah im Kern so aus:

  • MX der Domain ermitteln
  • SMTP-Session öffnen
  • RCPT TO:<postmaster@domain>
  • RCPT TO:<abuse@domain>
  • Ergebnis klassifizieren

Einige Server antworteten sauber:

  • 250 2.1.5 Ok – Empfänger akzeptiert
  • Andere waren ehrlich brutal:
  • 550 5.1.1 User unknown – Empfänger existiert nicht

Manche waren schlüpfrig:

  • 451 4.7.1 Try again later – temporär, könnte Rate-Limit sein
  • 550 5.7.1 Access denied – Policy-Block, manchmal blind
  • oder sie akzeptierten alles und bouncten später (Backscatter-Paradise)

M. baute Regeln. Nicht perfekt, aber besser als Bauchgefühl.

Die ersten Einträge in der Liste waren nicht „die Bösen“. Es waren oft schlicht:

  • kleine Firmen, die Mail „irgendwie“ hatten
  • Domains mit kaputten Weiterleitungen
  • „wir nutzen einen Provider“-Setups ohne Rollenpostfächer
  • oder verlassene Domains, die noch MX hatten, aber niemand mehr betreute

Und dann: große Namen. Weil große Namen nicht automatisch gute Hygiene bedeuten.
Das machte die Liste berühmt. Und brachte die ersten Feinde.

4) Die Gegenwehr – Agenten mögen keine Aufmerksamkeit, DNSBLs bekommen sie gratis

Sobald die Liste sichtbar war, passierten drei Dinge gleichzeitig:

  • Admins waren dankbar, weil es endlich ein automatisierbares Signal gab.
  • Betroffene waren wütend, weil sie plötzlich Konsequenzen spürten.
  • Spammer wurden neugierig, weil jede Liste auch ein Kartendienst ist.

M. bekam Mails – ironischerweise auf die eigenen Kontaktadressen, die natürlich existierten. Viele waren sachlich: „Wie komme ich runter?“ Andere waren… weniger sachlich.

In der Welt der DNSBLs ist „Runterkommen“ kein Yoga. Es ist Ops:

  • Alias abuse@ anlegen
  • Alias postmaster@ anlegen
  • Monitoring drauf
  • dann Retest / Delist

Aber hier lag der eigentliche Konflikt: Viele wollten nicht „fixen“, sie wollten „weg“. Und zwar sofort. Ohne Aufwand. Ohne Veränderung. Ohne Verantwortung.

In Agentensprache: Sie wollten den Wachmann bestechen, statt die Tür zu reparieren.

M. war nicht käuflich – schon weil das Projekt nicht so funktionierte. Du konntest nicht „zahlen“, damit SMTP plötzlich 250 sagt.

Das machte ihn gefährlich. Nicht durch Macht – durch Unbestechlichkeit. Eine seltene Sorte.

5) Der schmutzige Teil – wenn „Kontakt“ plötzlich selbst ein Angriffsziel ist

Je größer die Liste wurde, desto absurder wurden die Nebeneffekte.

Abuse-Postfächer sind Müllhalden, wenn du sie nicht verteidigst. Sobald klar war: „abuse@ existiert“, wurde es von manchen als Spamziel missbraucht.

Einige Betreiber reagierten vorhersehbar falsch:
Sie löschten abuse@ wieder. „Problem gelöst.“
Und landeten damit wieder in IGNORANT. Kreislauf geschlossen.

Andere machten’s richtig:

  • abuse@ als Ticket-Queue
  • harte Inbound-Filter (aber kein „User unknown“)
  • Rate-Limits
  • klare Auto-Responder mit Case-ID
  • und vor allem: menschliche Bearbeitung, wenn’s ernst wird

Und dann war da die technische Front: Last.

DNSBLs werden nicht „ab und zu“ befragt. Sie werden in Mailpipelines eingebaut – und dann feuert jede eingehende Verbindung Queries ab. Das kann klein anfangen und schnell grotesk werden.

M. musste plötzlich Dinge tun, die in keinem idealistischen Konzeptpapier stehen:

  • Anycast? Schön wär’s.
  • mehrere NS? Klar, aber kostet Zeit und Geld
  • Query-Rate begrenzen, ohne legitime Nutzer zu töten
  • Monitoring, sonst bist du blind
  • DoS-Abwehr, weil irgendwer’s „witzig“ findet

Agenten leben von Logistik. Und Logistik kostet.

Das Projekt, das als mahnender Zeigefinger begann, wurde zu Infrastruktur. Und Infrastruktur frisst Menschen.

6) Die philosophische Krise – wenn ein binärer Schalter moralische Debatten auslöst

Irgendwann war IGNORANT nicht mehr nur „eine Liste“. Es war ein Argument.

Die Debatten drehten sich nicht mehr um SMTP-Codes, sondern um Macht:

  • Darf man Domains „bestrafen“, weil sie nicht erreichbar sind?
  • Ist abuse@ wirklich Pflicht oder nur Tradition?
  • Wer kontrolliert die Liste?
  • Was ist mit False Positives?
  • Was ist mit Domains, die absichtlich keine Mail annehmen?

Die Wahrheit: Alle hatten ein bisschen recht, und genau das ist der Fluch der Netzpolitik.

Technisch ist es simpel: Ein Server akzeptiert oder akzeptiert nicht.

Operativ ist es komplex:
Manche Domains wollen gar kein SMTP, haben aber trotzdem MX wegen Legacy.
Manche Provider verstecken Rollenpostfächer hinter Formularen oder Portalen.
Manche blocken „fremde“ Tests, weil sie Abuse-Scanning für Angriff halten.
Und manche sind schlicht kaputt.

Die Liste war ein Hammer. Viele Probleme sind Nägel. Aber einige sind Glas.

M. wusste: Eine DNSBL ist immer zu grob für die Realität. Sie ist trotzdem nützlich, solange man sie als Signal nutzt – nicht als absolutistische Wahrheit.

Nur: Menschen lieben Absolutismus. Der ist bequem. Und bequem ist gefährlich.

7) Der Zeitenwandel – wenn Mega-Provider die Spielregeln ändern

Dann kam die nächste Welle: Zentralisierung.

Die Mailwelt kippte von „tausend kleine Server“ zu „ein paar riesige“.

Große Provider hatten ihre eigenen Systeme:

  • interne Reputation
  • Feedback-Loops
  • Abuse-Teams
  • automatisierte Takedowns
  • und vor allem: genug Personal, um nicht von einem DNSBL-Projekt abhängig zu sein

Gleichzeitig verschwanden viele kleine Betreiber – oder wurden zu Resellern, die keinen Zugriff mehr auf die eigentlichen Systeme hatten. Du konntest ihnen noch so oft sagen „macht abuse@“ – sie konnten oft nicht.

IGNORANT traf zunehmend die, die am wenigsten Hebel hatten.
Und verfehlte zunehmend die, die wirklich Einfluss hatten.

Das ist der Moment, in dem Agentenfilme normalerweise einen Twist haben: Der Held merkt, dass seine Waffe nicht mehr trifft, was sie treffen soll.

8) Der letzte Einsatz – Hardware stirbt, Menschen auch (nur anders)

Am Ende war es nicht der große Gegner, der IGNORANT beendete. Es war die klassische, schäbige Realität:

  • alte Hardware
  • Wartungsaufwand
  • sinkende Zeit
  • steigender Ärger
  • und das Gefühl, dass man gegen Windmühlen schraubt

Ein DNSBL-Projekt kann man nicht „halb“ betreiben. Wenn du’s tust, wirst du selbst zur Fehlerquelle. Stale Data ist Gift. Und wenn du eine Liste fütterst, die andere in Mailannahme-Policy einbauen, ist „ungepflegt“ ein Sicherheitsrisiko.

M. machte das einzig Verantwortliche: Er zog den Stecker.

Keine dramatische Abschiedsrede. Eher eine Notiz am Schaltschrank:
„Diese Maschine wird nicht mehr gewartet. Benutzung auf eigenes Risiko.“

Die Seite blieb als Geschichte. Als Warnung. Als Artefakt.

Wie ein altes Agentenhandbuch in einem Safe, das keiner mehr benutzt, aber jeder mal lesen sollte.

Field Notes – Was man aus der Akte mitnimmt (ohne Mythos)

A) Rollenpostfächer sind keine Folklore – sie sind Incident-Response-Mechanik

Wenn du Mail betreibst (direkt oder indirekt), brauchst du:

  • postmaster@domain – für SMTP-/Delivery-Probleme, Fehlkonfig, Policy
  • abuse@domain – für Missbrauch, Compromise, Spam, Phishing, Beschwerden

Nicht weil’s „nett“ ist – weil es operativ ist. Ohne erreichbaren Kanal wird jedes Problem langsamer, teurer, größer.

B) DNSBLs sind Werkzeuge – keine Orakel

  • Gut als Signal (Score, Tag, zusätzliche Prüfung)
  • gefährlich als harte Wahrheit (Reject ohne Kontext)

Wenn du so eine Liste nutzt: Logging, Exceptions, Monitoring. Keine Religion.

C) Tests müssen sauber sein

Ein einfacher, reproduzierbarer Ansatz:

domain=example.org
dig +short MX "$domain" | sort -n
mx=$(dig +short MX "$domain" | sort -n | head -1 | awk '{print $2}' | sed 's/\.$//')

# SMTP-Handshake – minimal
openssl s_client -starttls smtp -crlf -connect "$mx:25" <<EOF
EHLO test.invalid
MAIL FROM:<probe@test.invalid>
RCPT TO:<postmaster@$domain>
RCPT TO:<abuse@$domain>
QUIT
EOF

Interpretation:

  • 250 bei RCPT = existiert/akzeptiert
  • 550 5.1.1 = typischer „existiert nicht“
  • 451/421 = temporär – retesten, Rate-Limits beachten
  • „accept-all then bounce“ = Sonderfall – Backscatter-Risiko

D) Der richtige Fix ist banal – und genau deshalb wird er oft nicht gemacht

  • Aliases anlegen
  • auf ein Ticket-/Queue-System routen
  • Filtern/Rate-Limiting, aber kein „User unknown“
  • Monitoring + Eskalation

Das ist kein Hexenwerk. Es ist Hygiene. Genau das macht’s so unbequem.

Epilog – Warum diese Geschichte heute noch zählt

Die Mailwelt hat sich geändert. Die Grundprobleme nicht.

Wenn du heute eine Domain betreibst und irgendwo Mail berührst – direkt, über SaaS, über Provider – dann gilt immer noch:

Wenn man dich nicht erreichen kann, existierst du für Incident Response nicht.
Und das Netz ist voll von Leuten, die dir gerne helfen würden, bevor es eskaliert – aber nur, wenn ein Postfach am anderen Ende nicht „User unknown“ sagt.

RFC-Ignorant war keine perfekte Maschine. Aber es war ein klares Signal aus einer Zeit, in der das Netz noch stärker auf freiwillige Betriebskultur angewiesen war.

Eine Agentengeschichte, nur ohne Pistolen.
Stattdessen: DNS, SMTP, und ein 550, der die Welt erklärt.

Postfix SSL/TLS sichern mit TLSA, DANE und DNSSEC

Mein Domains sind nun schon seit langem per DNSSEC gesichert. Schnell habe ich auch TLSA-RECORDS für mein SSL/TLS X.509 Zertifikat des Webservers Apache veröffentlicht, damit die verschlüsselte Verbindung zu meiner Webseite ebenfalls per DANE gesichert ist.

DNSSEC: https://www.kernel-error.de/dnssec

DANE: https://www.kernel-error.de/dnssec/tls-ssl-zertifikatschecksummen-im-dns

Seit Januar diesen Jahres beherscht nun Postfix ebenfalls die Möglichkeit TLSA Records zu prüfen. Da mache ich natürlich mit!

Zuerst muss die Postfix Version natürlich passen. Kleiner 2.11 sollte es nicht sein, die Postfixversion zeigt sich schnell per:

$ postconf -d | grep mail_version
mail_version = 2.11.0

Mein Mailserver bietet natürlich schon immer die Möglichkeit einer verschlüsselten Verbindung an. Daher gehe ich einfach mal nicht näher darauf ein, wie man sein Postfix dazu überredet. Ganz kurz… Aktivieren lässt sich die Unterstützung für DANE / TLSA mit folgenden drei Konfigurationsänderungen:

$ postconf -e "smtpd_use_tls = yes"
$ postconf -e "smtp_dns_support_level = dnssec"
$ postconf -e "smtp_tls_security_level = dane"

Keine Sorge, alles bietet einen Failback an, so leidet die Kommunikation mit _nicht_ DANE fähigen Systemen nicht.

Zum erstellen des TLSA-RECORDS muss selbstverständlich nicht unbedingt der von mir in früheren Beiträgen erwähnte Hash-slinger eingesetzt werden. Openssl macht dieses fast genau so schnell.

$ openssl x509 -in postfix.pem -outform DER | openssl sha256
(stdin)= 94c8e1bdfff4f6d3fec0c4e2f26293d78870650bfd3534e77b93cdaccb77eb95

Aus diesem Hash erstelle ich nun den TLSA RECORD. Für die E-Mail Kommunikation ist es mir lieb, wenn der TTL (Lebensdauer) des Records nicht ZU lange ist. Bei einem Zertifikatswechsel dauert es sonst unnötig lange bis der neue Record gültig ist. Daher setzte ich ihn auf 1 Stunde.

_25._tcp.smtp.kernel-error.de. 1H IN TLSA 3 1 1 8cb0fc6c527506a053f4f14c8464bebbd6dede2738d11468dd953d7d6a3021f1
_465._tcp.smtp.kernel-error.de. 1H IN TLSA 3 1 1 8cb0fc6c527506a053f4f14c8464bebbd6dede2738d11468dd953d7d6a3021f1

Wie zu sehen ist biete ich den TLSA RECORD direkt für Port TCP 25 und TCP 465 an. Schnell nur noch testen ob der TLSA RECORD mit dig auch sauber abgefragt werden kann.

$ dig _25._tcp.smtp.kernel-error.de +dnssec +m

; <<>> DiG 9.8.4-rpz2+rl005.12-P1 <<>> _25._tcp.smtp.kernel-error.de +dnssec +m
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 28381
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 4, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;_25._tcp.smtp.kernel-error.de. IN A

;; AUTHORITY SECTION:
kernel-error.de.        86400 IN SOA ns1.kernel-error.de. root.kernel-error.de. (
                                20140102708 ; serial
                                10000      ; refresh (2 hours 46 minutes 40 seconds)
                                1800       ; retry (30 minutes)
                                604800     ; expire (1 week)
                                86400      ; minimum (1 day)
                                )
kernel-error.de.        86400 IN RRSIG SOA 7 2 86400 20150511054702 (
                                20140516054702 38150 kernel-error.de.
                                QXUpVl3myVAUGn/ox8J5aihAySHdWpojyPuhV5QKgDUy
                                qYRPyryWyBoGG+x5cGs0JpPBqQA3lRovAM4JFvC3hRmO
                                FU3fVTiYlvAJK7WsTSgPJLYpXrBnS+NN0O2UW3W+Ru1K
                                2P5dj+BWNO1wqXs+VU7WpMPwq/ESlK88hxXE1Gc= )
_25._tcp.smtp.kernel-error.de. 86400 IN NSEC _465._tcp.smtp.kernel-error.de. RRSIG NSEC TLSA
_25._tcp.smtp.kernel-error.de. 86400 IN RRSIG NSEC 7 5 86400 20150511054702 (
                                20140516054702 38150 kernel-error.de.
                                ToC8GtXFenieGjA32eoHACNGCg+tFr05vz6w9yiHYrDj
                                rHGBabc7MMjqUWNsf7L059YhR7dLoAPqhy2ZThWqFbRD
                                ZsfPQSgHIazEuKvOE7i2Ee/znU2d57X8nVkp8scUKZ1R
                                kGdK5DUDlAcYn0YdpjYaUTn2STdbM9IDcdrASPE= )

;; Query time: 0 msec
;; SERVER: ::1#53(::1)
;; WHEN: Mo Jan 27 08:50:36 2014
;; MSG SIZE  rcvd: 506

Schon lässt sich im Postfix Logfile erkennen ob Verbindungen getraut wird oder nicht.

Jan 27 08:32:02 mailserver postfix/smtp[3779]: Verified TLS connection established to mx02.example.de[99.88.12.167]:25: TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)
Jan 27 08:33:19 mailserver postfix/smtp[3779]: Untrusted TLS connection established to smtp2.example.de[2001:333:6661:99::34]:25: TLSv1 with cipher ADH-AES256-SHA (256/256 bits)

Wenn man mich fragt, ist die Kombination aus DNSSEC, DANE / TLSA deutlich besser als dieses hässliche EmiG. EmiG benötigt eine unnötig teure Zertifizierung durch den TüV, dieses kann sich nicht jeder leisten. Damit ist dieses „sichere“ Verfahren fast nur durch Unternehmen zu realisieren die genug Kohle haben. Kleinere werden damit einfach abgehängt. Verfahren die Sicherheit nur für „reiche“ zur Verfüfung stellen sollte man aus meiner Überzeugnung nicht unterstützen.

Eine weitere schnelle und einfache Möglichkeit seinen TLSA-RECORD des Mailservers / Postfix zu testen ist posttls-finger:

$ posttls-finger -t30 -T180 -c -L verbose,summary kernel-error.de
posttls-finger: initializing the client-side TLS engine                                                                                                                                                                          
posttls-finger: using DANE RR: _25._tcp.smtp.kernel-error.de IN TLSA 1 0 1 94:C8:E1:BD:FF:F4:F6:D3:FE:C0:C4:E2:F2:62:93:D7:88:70:65:0B:FD:35:34:E7:7B:93:CD:AC:CB:77:EB:95                                                       
posttls-finger: setting up TLS connection to smtp.kernel-error.de[2a02:c200:0:10:3:0:4297:1]:25                                                                                                                                  
posttls-finger: smtp.kernel-error.de[2a02:c200:0:10:3:0:4297:1]:25: TLS cipher list "aNULL:-aNULL:ALL:!EXPORT:!LOW:+RC4:@STRENGTH:!aNULL"                                                                                        
posttls-finger: smtp.kernel-error.de[2a02:c200:0:10:3:0:4297:1]:25: depth=1 verify=0 subject=/C=IL/O=StartCom Ltd./OU=Secure Digital Certificate Signing/CN=StartCom Class 2 Primary Intermediate Server CA                      
posttls-finger: smtp.kernel-error.de[2a02:c200:0:10:3:0:4297:1]:25: depth=1 verify=0 subject=/C=IL/O=StartCom Ltd./OU=Secure Digital Certificate Signing/CN=StartCom Class 2 Primary Intermediate Server CA                      
posttls-finger: smtp.kernel-error.de[2a02:c200:0:10:3:0:4297:1]:25: depth=0 verify=1 subject=/description=y0xkuso3gx7t8h0o/C=DE/ST=Nordrhein-Westfalen/L=Sprockh\xF6vel/O=Sebastian Van De Meer/CN=smtp.kernel-error.de/emailAddress=postmaster@kernel-error.de                                                                                                                                                                                                   
posttls-finger: smtp.kernel-error.de[2a02:c200:0:10:3:0:4297:1]:25: depth=0 matched end entity certificate sha256 digest 94:C8:E1:BD:FF:F4:F6:D3:FE:C0:C4:E2:F2:62:93:D7:88:70:65:0B:FD:35:34:E7:7B:93:CD:AC:CB:77:EB:95         
posttls-finger: smtp.kernel-error.de[2a02:c200:0:10:3:0:4297:1]:25: subject_CN=smtp.kernel-error.de, issuer_CN=StartCom Class 2 Primary Intermediate Server CA, fingerprint=E1:92:93:D4:CA:E9:5D:44:B5:CC:A4:15:1F:12:A6:E0:B5:C2:97:56, pkey_fingerprint=E9:84:8E:51:47:99:90:53:0B:2C:2E:1E:70:6E:DE:CA:A4:65:8A:C5                                                                                                                                             
posttls-finger: Verified TLS connection established to smtp.kernel-error.de[2a02:c200:0:10:3:0:4297:1]:25: TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)

So bei Fragen, einfach fragen 🙂


09-08-2014 Update

Ich habe zur Auswertung den Mailgraph etwas angepasst ( mailgraph Graphen um DANE erweitern ). Dieser wirft mir nun den unten stehenden Graphen für ausgehende Verbindungen raus.

SPF-Record erklärt: Schutz vor gefälschten E-Mails

Ich bin in der letzten Zeit immer mal wieder zu meinem SPF Record Beispiel gefragt worden. Ihr wisst schon… Diese beiden:

kernel-error.de.    IN  TXT "v=spf1 ip4:212.23.142.146 ip6:2001:7d8:8001:100::2 ptr:smtp.kernel-error.de mx a:smtp.kernel-error.de -all"
kernel-error.de.    IN  SPF "v=spf1 ip4:212.23.142.146 ip6:2001:7d8:8001:100::2 ptr:smtp.kernel-error.de mx a:smtp.kernel-error.de -all"

Ich versuche das ganze noch einmal etwas aufzuschlüsseln. Die genannten Beispiele sollen die Möglichkeiten zeigen, welche man hat um den SPF-RECORD zu erstellen. Der echte SPF-RECORD sollte aber so schlank wie irgendwie möglich sein. Denn er wird ja theoretisch bei jeder eingehenden E-Mail geprüft. Um so länger er ist und umso mehr geprüft werden muss umso mehr DNS Lookups müssen gemacht werden. Man hat nach RFC nur maximal 10 DNS Abfragen, eine davon hat man schon verbrannt um den eigentlichen SPF RECORD zu holen. Es bleiben also noch 9 🙂 Kommt man über diese 10 Abfragen stirbt alles mit der Meldung:
Results – PermError SPF Permanent Error: Too many DNS lookups

Ist auch OK so, denn wenn der empfangende Mailserver für jede eingehende E-Mail hunderte DNS lookups durchführen muss, tut er ja nichts anders mehr!

Gut, nun zu meinem Beispielrecord.

v=spf1 ==> Ist die Protokollversion
ip4:212.23.142.146 ==> Von dieser IPv4 Adressen dürfen E-Mails kommen.
ip6:2001:7d8:8001:100::2 ==> Von dieser IPv6 Adresse dürfen E-Mails kommen.
ptr:smtp.kernel-error.de ==> Es dürfen E-Mails von den PTR Adresse“n“ des Hosts smtp.kernel-error.de kommen.
mx ==> Es dürfen E-Mails vom MX (Mail Exchange) der Domäne kernel-error.de kommen.
a:smtp.kernel-error.de ==> Es dürfen E-Mails von den IPv4 / IPv6 Adressen des Hosts smtp.kernel-error.de kommen.
==> Kommt die E-Mail von einem -nicht zutreffenden- System gilt der SPF-Test immer als Fehlschlag
all ==> Das ganze passiert immer.

Bei den IP-Adressen kann ebenfalls ein ganzes Netz angegeben werden. Zum Beispiel: 212.23.142.146/24

Beim mx könnte eine andere Domäne oder Subdomäne stehen. Zum Beispiel: mx:smtp.kernel-error.de damit dürften dann E-Mails vom MX der Domäne smtp.kernel-error.de kommen. Natürlich muss es diesen MX auch geben!!! Es geht noch mehr… Zum Beispiel habe ich in einer weiteren Domain von mir nur folgendes stehen:
v=spf1 include:kernel-error.de -all

include:kernel-error.de ==> Gibt an das bitte der SPF RECORD von der Domain kernel-error.de abgefragt und angewandt werden soll. Damit gilt die SPF-Policy der Domain kernel-error.de. Ich muss also nur eine Policy pflegen und lasse alle anderen Domains nur auf diese verweisen 🙂

Die Abfrage würde dann so aussehen:

DNS record(s):
    vandemeer.de. 86400 IN SPF "v=spf1 include:kernel-error.de -all"
    kernel-error.de. 86400 IN SPF "v=spf1 ip4:212.23.142.146 ip6:2001:7d8:8001:100::2 -all"

Würde man nun den oben stehenden RECORD in die Zone kernel-error.de. werfen und ihn aktiv nutzen; Dann wird er funktionieren und absolut gültig sein. Das empfangende E-Mail System wird aber eine ganz Hand voll DNS Abfragen machen müssen um diese SPF Policy zu prüfen. Jetzt beantwortet sich sicher die Frage, warum ich einen anderen SPF-RECORD einsetzte als hier aufgeführt 😀 Denn die aufgeführten RECORDS sind schlicht ein Beispiel und keine Copy & Paste Vorlagen. Ok ok… Ich hätte das direkt genauer beschreiben sollen, hm?

Weniger ist im SPF RECORD also mehr. Man darf sich also überlegen welcher RECORD für seine Domain und sein System gerade der beste ist. Wenn es wechselnde IP Adresse gibt ist sicher ein A/AAAA RECORD besser, wenn sich dieser oft ändert dann ggf. ein MX der Domain oder ein ganzes Netz oder oder…

Mehr zum Lesen:

SPF
SPF-RECORD
SPF-RECORD erkärt

DMARC: Domain-Based Message Authentication, Reporting & Conformance (DMARC) einrichten

Habt ihr eigentlich schon etwas von DMARC (Domain-based Message Authentication, Reporting & Conformance) gehört? Nein… Dann dann haben wir das ja nun aufgeholt 😛

Im Grunde „erweitert“ DMARC die beiden Systeme SPF (Sender Policy Framework) und DKIM (DomainKeys Identified Mail). Warum und wie?!? Nun ja, beide Techniken sind erstmal ~nicht schlecht~. Setzt man sie ausgehend ein, fehlen dem Admin denn noch etwas die „Rückmeldungen“. OK, wenn etwas schief geht, jammern die User. Setzt man sie eingehend ein, würde es hin und wieder helfen wenn der „Absender“ einem etwas genauer sagen würde wie denn nun mit seinen Nachrichten umgegangen werden soll.

Hier springt nun DMAC -in die Bresche- (woher kommt eigentlich diese Redensart?). DMARC wird, wie bei SPF oder DKMI möglich, einfach als TXT-RECORD in der DNS Zone versenkt. Dort finden sich nun Informationen für den empfangenden Mailserver. Zum Beispiel kann angegeben werden wie viel Prozent der eingehenden E-Mails überhaupt gefiltert werden soll (pct), wie hart bei Fehlern im SPF (aspf) und DKIM (adkim) umgegangen werden soll, wie mit E-Mails der Haupt- (p) oder Subdomänen (sp) umgegangen werden soll und was tierisch geil für den Admin des Absendenden E-Mail Systems ist…. An welche E-Mail Adresse ein forensischer (das Wort trifft es, ich finde es aber doof :-P) Bericht (ruf) und wohin eine tägliche Zusammenfassung (rua) gesendet werden soll.

Diese Berichte schlagen normalerweise als E-Mail mit einem komprimierten ZIP-File im Gebäck auf. In diesem ZIP-File steckt dann ein XML-File (*würk* XML.. für die Auswertung denn noch geil). Diese kann man nun auswerten. So kann der Admin des absendenden E-Mail Systems sehen wie gut oder schlecht seine Bemühungen greifen. Er wird schnell über Probleme informiert und kann erkennen ob und wie stark seine Domain gerade -missbraucht- wird.

Eine E-Mail mit ZIP-File lässt sich sehr einfach automatisch auspacken und die XML Datei wird dann von irgendeinem Stück Software gefressen. Heraus kommt ein täglicher Bericht für den Admin. Ok, man könnte es schön bunt machen, dann kann man es auch einer Krawatte zum klicken geben 🙂

Klar muss der Empfänger es unterstützen, sonst bringt das alles nix. Aber jeder Absender, der bereits SPF und DKIM einsetzt, kann seinen DMARC Record schon mal erstellen, hm?

Ich probiere eine kurze Erklärung des DMARC TXT RECORDS an meinem…

_dmarc.kernel-error.de  IN TXT  "v=DMARC1; pct=100; rua=mailto:postmaster@kernel-error.de; ruf=mailto:postmaster@kernel-error.de; adkim=s; aspf=s; p=quarantine; sp=quarantine"

_dmarc. ==> ist halt der „Bezeichner“
kernel-error.de ==> japp die Domain
IN TXT ==> Internet und Text
„“ ==> Dazwischen ist der Text
; ==> Trennt die Optionen
v=DMARC1 ==> Protokollversion, hier also 1
pct=100 ==> 100% meiner vermeintlichen Nachrichten sollen gefiltert werden
rua=mailto:postmaster@kernel-error.de ==> Zusammenfassung geht an postmaster@kernel-error.de
ruf=… ==> der forensiche Bericht geht ebenfalls an den Postmaster
adkim=s ==> DKIM soll nicht relaxed (r) sondern strict (s) ausgewertet werden
aspf=s ==> auch strict
p=quarantine ==> Fehlgeschlagenes der Hauptdomäne sollen als SPAM markiert werden.
sp=quarantine ==> bei der Subdomäne auch.

Noch eine Kleinigkeit. Wenn man mehrere Domains betreut und die Berichte an eine zentrale E-Mail Adresse senden möchte dann muss man noch etwas beachten. Denn sollen die Berichte an eine E-Mail Adresse außerhalb der Domain des DMARC RECORDS gesendet werden, dann muss dieses in der Empfängerdomäne „erlaubt“ werden. Dieses geht über einen gesonderten TXT RECORD.

kernel-error.com._report._dmarc.kernel-error.de TXT "v=DMARC1"

Wenn man diesen RECORD als Beispiel nimmt, würde er in der Zone kernel-error.DE stehen. Damit würden die Berichte aus der Zone kernel-error.COM an die Adresse xyz@kernel-error.de zugestellt werden können.

Noch Fragen? Na dann fragen 😀


UPDATE 12.12.2013

Ok ok… da die Frage jetzt ein paar mal aufgekommen ist, wie ein solcher Report aussieht…. Hier ein Beispiel: >> klick <<

Zur besseren Ansicht kann ich auch hier nur wieder auf dmarcian.com verlinken. Hier gibt es einen XML du Human Konverter 🙂 

Frage beantwortet?

« Ältere Beiträge

© 2026 -=Kernel-Error=-RSS

Theme von Anders NorénHoch ↑