Swiftmailer mit Verschlüsselungs Zertifikat

Hallo,

Der Swiftmailer ist eine super Bibliothek, mit der man zB ein Kontaktformular auf einer Website realisieren kann. Die Eingaben kann man dann mittels Swiftmailer als Email verschicken.

Auch eine ssl Verschlüsselung zur Tramsportsicherung zum smtp-Server ist sehr einfach zu realisieren. Insgesamt ist das Ding sehr mächtig.

Woran ich aber seit Tagen scheitere, ist die Email mittels Zertifikat zu signieren und/oder zu verschlüsseln. So wie ich das verstehe, muss man dazu eine Bibliothek Namens OpenSSL auf seinem Webserver installieren und in PHP irgendwie einbinden.

Hat Jemand zu diesem Thema Erfahrung? Ich habe viel gesucht, komme dabei aber nicht zum Ziel.
Wäre echt super…

Ich habe noch nie etwas derartiges gemacht aber hoffentlich helfen die meine Fähigkeiten mit Google umzugehen.

http://de.php.net/manual/de/function.openssl-pkcs7-sign.php

lg :slight_smile:

Vielen Dank, aber da bist Du schon ein Schritt weiter als ich.

Swiftmailer (http://swiftmailer.org/), aktuelle Version 5.0.3 von Dezember 2013 hat eine umfangreiche Dokumentation. Zum Thema Verschlüsselung/Signierung folgendes:

[I]Signed/Encrypted Message
To increase the integrity/security of a message it is possible to sign and/or encrypt an message using one or multiple signers.

S/MIME

S/MIME can sign and/or encrypt a message using the OpenSSL Extension.

$message = Swift_SignedMessage::newInstance();
$smimeSigner = Swift_Signers_SMimeSigner::newInstance();
$smimeSigner->setSignCertificate(‚/path/to/certificate.pem‘, ‚/path/to/private-key.pem‘);
$message->attachSigner($smimeSigner);
[/I]
Ich verstehe das so, dass man die OpenSSL Bibliothek ( http://www.openssl.org/ , aktuell V1.01.1F vom 06.01.2014) auf dem Webserver zusätzlich als Extension installieren muss. Bin ich soweit noch richtig?

Und wenn ja, wie geht das denn?

Wie das geht ist hier beschrieben:
http://www.php.net/manual/de/openssl.installation.php

Allerdings geht das nur, wenn Du einen eigenen Server bzw. die Möglichkeit hast so eine Erweiterung überhaupt zu integrieren. Solltest Du einen eigenen Server haben, würde sich zunächst ein Blick in den Paketmanager des verwendeten Betriebssystems lohnen. Die meisten Linux-Distributionen haben solche Pakete bereits mit an Bord und die Installation ist fix erledigt. Hast Du diese Möglichkeit nicht, müsstest Du o.g. Link folgen.

Außerdem solltest Du mittels phpinfo() vorher mal prüfen, ob openssl nicht bereits auf deinem Webspace/Server vorhanden ist.

Einen eigenen Webserver betreibe ich nicht.

Das ist dann schon mal was: Ich habe phpinfo () auf einer Testseite hochgeladen und siehe da:
[SIZE=5][…]
openssl[/SIZE]
OpenSSL support enabled
OpenSSL Library Version OpenSSL 0.9.8o 01 Jun 2010
OpenSSL Header Version OpenSSL 0.9.8o 01 Jun 2010
[…]

Demnach ist openSSL auf „meinem“ Webserver bereits installiert.

Muss ich evtl. in meinem PHP Dokument das openssl aktivieren / integrieren &/ compilieren?

… by the way:

steht in der Antwort Tabelle auf phpinfo() irgendwas, was besser nicht öffentlich sein sollte?

Wenn ja, dann sollte ich vermutlich die Website mit dem phpinfo() Befehl schnell wieder löschen…

Was passiert denn wenn Du swiftmail ausführst? Führt das zu einer Fehlermeldung? Oder warum kommst Du auf die Idee openssl könnte bei dir nicht aktiv sein? Wenn es in phpinfo steht, ist es auch aktiv.

Und ja, phpinfo() solltest Du nur kurze Zeit online halten.

Also das funktioniert. Es wird eine E-Mail sogar in SSL Verschlüsselung zum smtp übertragen:

<?php require_once "Swift-5.0.3/lib/swift_required.php"; // Swift initialisieren // Create the Transport the call setUsername() and setPassword() $transport = Swift_SmtpTransport::newInstance('smtp.1und1.de', 587, 'ssl') ->setUsername('mein-username-beim-Email-Server') ->setPassword('und-mein PW-dazu') ; // Create the Mailer using your created Transport $mailer = Swift_Mailer::newInstance($transport); $message = Swift_Message::newInstance(); // Ein Objekt für die Mailnachricht. $message ->setFrom(array([EMAIL]'anfrage@meine-domain.de'[/EMAIL] => 'Anfrage vom Formmailer')) ->setTo(array([EMAIL]'ziel@email.de'[/EMAIL])) ->setSubject('Betreff der Mailer EMail'); $mailtext = "Das ist jetzt der Mail-text"; $message->setBody($mailtext, 'text/plain'); $mailer = Swift_Mailer::newInstance(Swift_MailTransport::newInstance()); $result = $mailer->send($message); if ($result == 0) { die("Mail konnte nicht versandt werden."); header("Location: ' http://danke-fuer-das-senden.html '"); exit; } header("Content-type: text/html; charset=utf-8"); ?>

Ich weiß aber leider nicht, wie ich nun die Verschlüsselung der Nachricht, wie in der Dokumentation angegeben, einbauen soll:
// $message = Swift_SignedMessage::newInstance();
// $smimeSigner = Swift_Signers_SMimeSigner::newInstance();
// $smimeSigner->setEncryptCertificate(‚/Certificate/mein.PEM‘);
// $message->attachSigner($smimeSigner);
// $smimeSigner->setSignThenEncrypt(false);

Ich schaffe es nicht diese 5 Zeilen so zu integrieren, dass es geht.

Hast Du bereits in deinem Code.

// $smimeSigner = Swift_Signers_SMimeSigner::newInstance();
// $smimeSigner->setEncryptCertificate(‚/Certificate/mein.PEM‘);
// $message->attachSigner($smimeSigner);
// $smimeSigner->setSignThenEncrypt(false);

Müsstest Du irgendwo nach dem Vorkommen von oben genannter Zeile, die bereits vorhanden ist, einfügen.

Wichtig dürfte dann noch sein, dass Du dein Zertifikat anstelle von mein.PEM einfügst. Hast Du das nicht zur Verfügung und hier nicht korrekt genannt, wird es auch nichts.

Ich habe die Zeilen anstelle der vorhandenen $message eingefügt:

<?php require_once "Swift-5.0.3/lib/swift_required.php"; // Swift initialisieren // Create the Transport the call setUsername() and setPassword() $transport = Swift_SmtpTransport::newInstance('smtp.1und1.de', 587, 'ssl') ->setUsername('smtp-username') ->setPassword('smtp-pw') ; // Create the Mailer using your created Transport $mailer = Swift_Mailer::newInstance($transport); // $message = Swift_Message::newInstance(); // funktionierende Version ohne Verschlüsselung $message = Swift_SignedMessage::newInstance(); $smimeSigner = Swift_Signers_SMimeSigner::newInstance(); $smimeSigner->setSignCertificate('/Certificate/mmg.crt', '/Certificate/mmg.crt'); $smimeSigner->setEncryptCertificate('/Certificate/rg.crt'); $message->attachSigner($smimeSigner); // $smimeSigner->setSignThenEncrypt(false); $message ->setFrom(array('absender-email' => 'Name der Absender EMail')) ->setTo(array('ziel-EMail')) ->setSubject('Betreff der EMail'); $mailtext = "Das ist jetzt der Mail-text ohne"; $message->setBody($mailtext, 'text/plain'); $mailer = Swift_Mailer::newInstance(Swift_MailTransport::newInstance()); $result = $mailer->send($message); if ($result == 0) { die("Mail konnte nicht versandt werden."); } header("Location: ' http://danke-Anfrage.html '"); exit; header("Content-type: text/html; charset=utf-8"); ?>

Und dafür bekomme ich diese Fehlermeldung:

Warning: tempnam() [function.tempnam]: SAFE MODE Restriction in effect. The script whose uid is 1839 is not allowed to access /tmp owned by uid 0 in /var/www/web628/html/Swift-5.0.3/lib/classes/Swift/ByteStream/TemporaryFileByteStream.php on line 20
Fatal error: Uncaught exception ‚Swift_IoException‘ with message ‚Failed to retrieve temporary file name.‘ in /var/www/web628/html/Swift-5.0.3/lib/classes/Swift/ByteStream/TemporaryFileByteStream.php:23 Stack trace: #0 /var/www/web628/html/Swift-5.0.3/lib/classes/Swift/Signers/SMimeSigner.php(214): Swift_ByteStream_TemporaryFileByteStream->__construct() #1 /var/www/web628/html/Swift-5.0.3/lib/classes/Swift/SignedMessage.php(104): Swift_Signers_SMimeSigner->signMessage(Object(Swift_SignedMessage)) #2 /var/www/web628/html/Swift-5.0.3/lib/classes/Swift/SignedMessage.php(78): Swift_SignedMessage->doSign() #3 /var/www/web628/html/Swift-5.0.3/lib/classes/Swift/Transport/MailTransport.php(144): Swift_SignedMessage->toString() #4 /var/www/web628/html/Swift-5.0.3/lib/classes/Swift/Mailer.php(86): Swift_Transport_MailTransport->send(Object(Swift_SignedMessage), Array) #5 /var/www/web628/html/test2.php(35): Swift_Mailer->send(Object(Swift_SignedMessage)) #6 {main} thrown in /var/www/web628/html/Swift-5.0.3/lib/classes/Swift/ByteStream/TemporaryFileByteStream.php on line 23

Was mir auffällt, ist, dass wenn ich den Pfad zu den Certifikaten falsch schreibe (ZB /falsch/rg.crt), dann ändert sich die Fehlermeldung nicht. Deswegen glaube ich, dass der Fehler schon früher passieren muss.

Das sieht mir so aus als würde Swiftmailer versuchen im /tmp-Verzeichnis etwas zu schreiben - der Server verhindert dies jedoch. In dem Fall müsstest Du die Serverkonfiguration selbst prüfen, angefangen von den PHP-Einstellungen, und vergleichen was Swiftmailer hier als Anforderungen setzt.

Ja, genau das scheint es zu sein! Ich habe nach mehreren Tagen es geschafft, eine Antwort vom Swiftmailer-Team zu bekommen:

Hello,
In fact, you need to set a tmp folder inside your safemode restricted directory (probably doc_root) Check more infos about safe mode, it’s usually used by shared hosting providers to secure users source code.
It’s a deprecated and dangerous security but few providers really care how to implement things correctly (by using open_basedir) http://php.net/manual/en/features.safe-mode.php

Folgende Prozedur erzeugt den Fehler beim Aufruf der Tempnam Funktion:

public function __construct()
{
[SIZE=5] [/SIZE][SIZE=5] $filePath = tempnam(sys_get_temp_dir(), ‚FileByteStream‘);[/SIZE]

    if ($filePath === false) {
        throw new Swift_IoException('Failed to retrieve temporary file name.');
    }

    parent::__construct($filePath, true);
}

Könnt Ihr mir da irgendwie weiterhelfen?
Folgende Pfadstruktur habe ich bei meinem Webspace. liegt es daran dass der Ordner phptmp und nicht nur tmp heißt?

[ATTACH=full]3623[/ATTACH]

Vielen Dank bis hierhin…

Als kleiner Tipp:

Schreibe

[php][/php]

um deinen PHP Code damit wir es besser lesen können. :slight_smile:

Jupp - geht klar

Gruß aus dem verschneiten Kiel

Ich würde dir raten dich an deinen Webhoster zu wenden.

Ja, vielen Dank, die Anfrage läuft.

Nur zu meinem Verständnis:
Der Fehler wird durch den Aufruf dieser Funktion ausgelöst:
[PHP]
public function __construct()
{
$filePath = tempnam(sys_get_temp_dir(), ‚FileByteStream‘);

if ($filePath === false) {
throw new Swift_IoException(‚Failed to retrieve temporary file name.‘);
}
parent::__construct($filePath, true);
}
[/PHP]

vermutlich weil in der PHP.ini, die der Hoster vorgibt, die Funktion „sys_get_temp_dir()“ kein richtiges Verzeichnis ergibt.

Wenn das so wäre, warum kann ich nicht einfach ein Verzeichnis vorgeben im Sinne von:
[PHP]
$filePath = tempnam(‚/MeinTMP‘, ‚FileByteStream‘);
[/PHP]

(ich hab es mit vorhanden Verzeichnissen probiert, es ging nicht).

Sobald ich eine Antwort vom Hoster habe, melde ich mich…

Gelöst:
Es wurde die Funktion sys_get_temp_dir() aufgerufen, die aber durch Hosterseitige PHP Einstellung kein erlaubtes Verzeichnis ergibt. Ich habe daher einfach ein „erlaubtes“ Verzeichnis manuell gesetzt - und schon läuft alles.

Ich habe in der Zwischenzeit mehrere Hoster hiermit getestet, in allen Fällen gab die Funktion sys_get_temp_dir() kein erlaubtes Verzeichnis zurück, es scheint sich um eine gebräuchliche Einstellung der Hoster zu halten, die diese Funktion unbrauchbar macht.

Ich versende nun Zertifikat-signierte und auch zusätzlich per Zertifikat verschlüsselte EMails ohne User-EMail-Client (=stabiler).

Vielen Dank für Eure Hilfe.