PHP - Swiftmailer с использованием STARTTLS и самозаверяющих сертификатов


Я пытаюсь отправить электронное письмо с помощью php и swiftmailer, используя STARTTLS, но я получаю ошибку сертификата. У меня есть корневой доступ к SMTP-серверу, и используемый сертификат является самозаверяющим. Я использую Debian на обеих машинах (веб-сервер и smtp-сервер)

PHP message: PHP Warning: stream_socket_enable_crypto(): SSL operation failed with code 1. OpenSSL Error messages: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed in [..]/lib/classes/Swift/Transport/StreamBuffer.php on line 97 PHP message: PHP Fatal error: Uncaught exception 'Swift_TransportException' with message 'Unable to connect with TLS encryption' in [..]/lib/classes/Swift/Transport/EsmtpTransport.php:294

Нужно ли мне где-то добавлять свой собственный сертификат, чтобы его приняли? Или это какая-то ошибка конфигурации OpenSSL?

Author: David Ventura, 2014-11-12

3 answers

Swiftmailer теперь обновлен, чтобы включить опцию для этого. Теперь ее можно решить с помощью метода setStreamOptions из вашего экземпляра Swift_SmtpTransport вместо редактирования класса swift.

$transport = Swift_SmtpTransport::newInstance('smtp.server.com', 123, 'tls')
    ->setUsername('username')
    ->setPassword('password')
    ->setStreamOptions(array('ssl' => array('allow_self_signed' => true, 'verify_peer' => false)));
 13
Author: Dave Kennard, 2016-03-15 13:01:52

У меня такая же проблема с использованием Swiftmailer в Laravel.

Похоже, что в Swiftmailer для этого нет возможности. Чистым решением было бы добавить свой собственный корневой центр сертификации на свой сервер и подписать сертификат почтового сервера с этим центром сертификации. После этого сертификат будет действителен. См., например, этот учебник.

В любом случае, быстрый грязный взлом, который вам не следует использовать, будет заключаться в редактировании swiftmailer\swiftmailer\lib\classes\Swift\Transport\StreamBuffer.php. В _establishSocketConnection() строке 253 заменить:

$options = array();

С чем-то вроде это:

$options = array('ssl' => array('allow_self_signed' => true, 'verify_peer' => false));

Это изменит параметры ssl stream_context_create() (несколькими строками ниже $options):

$this->_stream = @stream_socket_client($host.':'.$this->_params['port'], $errno, 
    $errstr, $timeout, STREAM_CLIENT_CONNECT, stream_context_create($options));
 13
Author: PiTheNumber, 2014-11-24 14:09:36

Вам не нужно редактировать файлы /vendor. Вы можете указать (недокументированные) параметры в своем файле config/mail.php:

'stream' => [
    'ssl' => [
        'allow_self_signed' => true,
        'verify_peer' => false,
        'verify_peer_name' => false,
    ],
],

Вы можете проверить это самостоятельно в vendor/laravel/framework/src/Illuminate/Mail/TransportManager.php в строке ~50:

...
if (isset($config['stream'])) {
    $transport->setStreamOptions($config['stream']);
}
...
 5
Author: Alex, 2016-12-21 16:47:14