PHP - 使用 STARTTLS 和自签名证书的 Swiftmailer
Posted
技术标签:
【中文标题】PHP - 使用 STARTTLS 和自签名证书的 Swiftmailer【英文标题】:PHP - Swiftmailer using STARTTLS and self signed certificates 【发布时间】:2015-01-09 20:29:19 【问题描述】:我正在尝试使用 STARTTLS 使用 php 和 swiftmailer 发送电子邮件,但出现证书错误。我对 SMTP 服务器具有 root 访问权限,并且使用的证书是自签名的。 我在两台机器(Web 服务器和 smtp 服务器)上都使用 Debian
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 配置错误?
【问题讨论】:
【参考方案1】:编者注:禁用 SSL 验证具有安全隐患。如果不验证 SSL/HTTPS 连接的真实性,恶意攻击者可以冒充一个受信任的端点(例如 GitHub 或其他一些远程 Git 主机),您将容易受到 Man-in-the-Middle Attack 的攻击。
在将其用作解决方案之前,请确保您完全了解安全问题。
Swiftmailer 现在已经更新为包含一个选项。现在可以使用 Swift_SmtpTransport
实例中的 setStreamOptions
方法解决它,而不是编辑 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)));
【讨论】:
你在哪里创建了这些行? @WilliamLepinski 您只需在代码中创建 Swift_SmtpTransport 实例的任何位置调用 setStreamOptions 即可。如果您不确定如何使用 Swift Mailer,请参阅此处的示例:swiftmailer.org/docs/sending.html 遵循该示例,但从 Swift_SmtpTransport 实例添加对 setStreamOptions 的调用。 这是你能做的最糟糕的事情,禁用 TLS 安全性的所有优点。【参考方案2】:我在 Laravel 中使用 Swiftmailer 时遇到了同样的问题。
在 Swiftmailer 中似乎没有此选项。干净的解决方案是将您自己的root CA 添加到您的服务器并使用此 CA 签署您的邮件服务器证书。证书将在此之后有效。参见例如this tutorial。
编者注:禁用 SSL 验证具有安全隐患。如果不验证 SSL/HTTPS 连接的真实性,恶意攻击者可以冒充一个受信任的端点(例如 GitHub 或其他一些远程 Git 主机),您将容易受到 Man-in-the-Middle Attack 的攻击。
在将其用作解决方案之前,请确保您完全了解安全问题。
无论如何,一个你不应该使用的快速肮脏的技巧是编辑swiftmailer\swiftmailer\lib\classes\Swift\Transport\StreamBuffer.php
。在_establishSocketConnection()
第 253 行替换:
$options = array();
类似这样的:
$options = array('ssl' => array('allow_self_signed' => true, 'verify_peer' => false));
这将改变stream_context_create() 的ssl options($options
下面几行):
$this->_stream = @stream_socket_client($host.':'.$this->_params['port'], $errno,
$errstr, $timeout, STREAM_CLIENT_CONNECT, stream_context_create($options));
【讨论】:
@miken32 感谢您的编辑和警告。您对此还不够清楚。永远不要在生产中禁用它!切勿使用此 hack 提交代码。 实际上,我将您所做的编辑中的文本复制到了另一个帖子中,哈哈。试图为这个问题找到一个重复的目标,并不断遇到所有这些“禁用验证”的答案。 :( @miken32 你成就了我的一天 :D 不确定这段文字是否真的来自我。无论如何,如果您需要接受您的自签名证书,您必须创建一个根/CA 证书作为源并将根添加到您的系统。 askubuntu.com/questions/73287/…【参考方案3】:编者注:禁用 SSL 验证具有安全隐患。如果不验证 SSL/HTTPS 连接的真实性,恶意攻击者可以冒充一个受信任的端点(例如 GitHub 或其他一些远程 Git 主机),您将容易受到 Man-in-the-Middle Attack 的攻击。
在将其用作解决方案之前,请确保您完全了解安全问题。
您不需要编辑/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']);
...
不用说,绕过对等验证具有巨大的安全隐患(读取漏洞)。我想这个解决方案适用于一些开发或本地环境,从不在生产环境中,甚至在 Internet/公共可用的应用程序中。
【讨论】:
【参考方案4】:编者注:禁用 SSL 验证具有安全隐患。如果不验证 SSL/HTTPS 连接的真实性,恶意攻击者可以冒充一个受信任的端点(例如 GitHub 或其他一些远程 Git 主机),您将容易受到 Man-in-the-Middle Attack 的攻击。
在将其用作解决方案之前,请确保您完全了解安全问题。
对我来说,我必须将 $transport->setStreamOptions(array('ssl' => array('allow_self_signed' => true, 'verify_peer' => false, 'verify_peer_name' => false)));
添加到 Mailer.php 文件中,请参阅:
/**
* Returns the SMTP transport
*
* @return \Swift_SmtpTransport
*/
protected function getSmtpInstance(): \Swift_SmtpTransport
$transport = new \Swift_SmtpTransport();
$transport->setTimeout($this->config->getSystemValue('mail_smtptimeout', 10));
$transport->setHost($this->config->getSystemValue('mail_smtphost', '127.0.0.1'));
$transport->setPort($this->config->getSystemValue('mail_smtpport', 25));
if ($this->config->getSystemValue('mail_smtpauth', false))
$transport->setUsername($this->config->getSystemValue('mail_smtpname', ''));
$transport->setPassword($this->config->getSystemValue('mail_smtppassword', ''));
$transport->setAuthMode($this->config->getSystemValue('mail_smtpauthtype', 'LOGIN'));
$smtpSecurity = $this->config->getSystemValue('mail_smtpsecure', '');
if (!empty($smtpSecurity))
$transport->setEncryption($smtpSecurity);
$streamingOptions = $this->config->getSystemValue('mail_smtpstreamoptions', []);
if (is_array($streamingOptions) && !empty($streamingOptions))
$transport->setStreamOptions($streamingOptions);
/* EDIT - allow self-signed mail cert */
$transport->setStreamOptions(array('ssl' => array('allow_self_signed' => true, 'verify_peer' => false, 'verify_peer_name' => false)));
/* EDIT end */
return $transport;
我是从另一个链接得到的,现在找不到了。
一个认为我对其他答案所做的额外工作是指定'verify_peer_name' => false
【讨论】:
以上是关于PHP - 使用 STARTTLS 和自签名证书的 Swiftmailer的主要内容,如果未能解决你的问题,请参考以下文章
Web Server CA证书签名步骤和自签名测试,支持多域名