DKIM Signatur für E-Mails einrichten

Zum guten Ton beim Versenden von E-Mails zählt die Signierung via DKIM (DomainKeys Identified Mail). Das Verfahren wurde in Zusammenarbeit mit einigen großen Firmen – darunter auch Microsoft, Cisco und Yahoo – entwickelt und hat sich dabei zu einer Art Standard etabliert. Hier folgt ein Guide zum Einrichten einer DKIM Signatur für E-Mails.

Dieser Guide bezieht sich auf die Erweiterung von einzelnen E-Mails mit DKIM, was über den SwiftMailer gesteuert wird. Viel einfacher noch ist die Verarbeitung von DKIM über den Mail-Server.

DKIM ist kein muss, aber ein Meilenstein, wenn man nicht im Spam-Filter der bekannten E-Mail-Provider hängen bleiben möchte. Der Empfänger hat sogar die Möglichkeit, die E-Mail zu verweigern oder auszusortieren, wenn keine Signatur vorhanden ist oder diese nicht valide ist.

Was passiert da überhaupt?

Das Verfahren basiert auf asymmetrischer Verschlüsselung. Unser Server muss also einen öffentlichen und einen privaten Schlüssel bereitstellen.

Zuerst wird ein Hash aus Header und Body der E-Mail erzeugt. Dieser wird mit unserem privaten Schlüssel (+ zusätzlich mit Base64) kodiert und als neuer Wert im Header hinzugefügt. Der Empfänger geht dann die Schritte rückwärts: Erst Base64 auflösen, den erhaltenen Wert mit dem öffentlichen Schlüssel des Servers entschlüsseln und dann selbst den Hash-Wert der E-Mail ermitteln und beides vergleichen. Stimmt der entschlüsselte Hash mit dem eigens generierten überein, haben wir alles richtig gemacht.

Das Schlüsselpaar erzeugen

Da die Verschlüsselung mit RSA vonstatten geht, könnte man theoretisch das übliche sh-keygen -t rsa verwenden. Sollte man aber nicht!!! Aus verschiedensten Gründen werden diese Schlüssel nicht akzeptiert. Ein Grund könnte die Schlüssellänge, ein anderer der häufige Beginn der Folge mit „AAA“ sein (zu linear). Man verwende hierfür besser openssl in einem Verzeichnis außerhalb unseres Projektes:

openssl genrsa -out dkim.priv 1024
openssl rsa -in dkim.priv -pubout > dkim.pub

Mit genrsa wird der private Schlüssel mit einer Länge von 1024 Bit erzeugt. Die 1024 Bit sind relativ sicher und passen gut in einen TXT Record. Mit rsa wird der öffentliche Schlüssel aus dem privaten erzeugt.

Während der private Key bleiben kann, muss der öffentliche Teil in ein TXT Record auf einer speziellen Subdomain gepresst werden. Lautet der Name meiner Domain „example.com“, muss eine Subdomain „Selektor._domainkey.example.com“ erstellt werden, die einen TXT Record der Form

v=DKIM1; p=MIG...P/abq2FKPJ6G3rgx5adsGKvnmkMadSwIDAQAB

enthält. Hierbei wird nur der Schlüssel, ohne weitere Informationen wie „ssh-rsa“ oder dem Domainnamen, benötigt. Zum „Selektor“ gleich mehr!

DKIM implementieren (SwiftMailer)

/** @var Swift_Message $message */
$message = Swift_Message::newInstance();
$message->setSubject("a subject");
$message->setFrom(['example@example.com' => 'example Name']);
$message->setReplyTo(['example@example.com' => 'example Name']);
$message->setTo('recipient@other-website.com');
$message->setBody('This is a <strong>wonderful</strong> body!', 'text/html');

// build DKIM signer
$message->attachSigner(
    Swift_Signers_DKIMSigner::newInstance(
        file_get_contents('/path/to/my/private/key'),
        'example.com',
        'this_is_the_selector_string'
    )
);

Wie in diesem kleinen Beispiel zu sehen, übernimmt der SwiftMailer die Aufgaben für uns. Alles was wir ihm geben müssen ist der private Schlüssel (mit Kommentarzeilen, so wie er erstellt wurde!), den Domainnamen der Webseite von der wir senden und einen Selektor.

Der Selektor ist eine beliebige Zeichenkette, der beim SwiftMailer angegeben und auf dem Server als Subdomain existieren muss (siehe oben). Der Empfänger weiß durch diesen Selektor, welchen TXT-Record er erfragen muss.

Fehlersuche

In einem unserer Projekte war die Identifizierung kein Problem, aber funktioniert hatte das Verfahren trotzdem nicht. Da DKIM sowohl Header, als auch Body hasht, ist es manchmal wichtig zu überprüfen, was da alles drin steckt…

Wir hatten zusätzliche Header in der Mail angebracht, allerdings erst, nachdem die Signatur schon vollständig erzeugt wurde. Somit hat der Empfangs-Server mit anderen Headern berechnet, als wir…

Statt die Reihenfolge zu ändern, kann man dem Signer aber auch sagen, welche Header-Felder denn konkret beachtet bzw. ignoriert werden sollen.

// add additional headers
$headers = $message->getHeaders();
$headers->addTextHeader('X-Mailer', 'PHP v'.phpversion());
$headers->addParameterizedHeader('Content-Type', 'text/html', ['charset' => 'utf-8']);

// create a signer
$signer = \Swift_Signers_DKIMSigner::newInstance(
    file_get_contents('/path/to/my/private/key'),
    'example.com',
    'this_is_the_selector_string'
);

// ignore the additional headers
$signer->ignoreHeader('Content-Transfer-Encoding');
$signer->ignoreHeader('X-Swift-Return-Path');
$signer->ignoreHeader('X-Mailer');

// add the signer
$message->attachSigner($signer);

// ...

Fazit

Das Einrichten einer DKIM Signatur für E-Mails mit dem SwiftMailer ist eine gute Alternative, wenn DKIM nicht Server-weit eingerichtet wurde. Besonders bei Hostern wie Strato, Domainfactory oder anderen, bei deren Paketen man vielleicht nicht genügend Zugriffe hat, um dies einzurichten, ist dieser Ansatz eine Lösung.

Kommentar hinterlassen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert