【问题标题】:PHP - Swiftmailer using STARTTLS and self signed certificatesPHP - 使用 STARTTLS 和自签名证书的 Swiftmailer
【发布时间】: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 配置错误?

【问题讨论】:

    标签: php smtp certificate swiftmailer self-signed


    【解决方案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

      【讨论】:

        猜你喜欢
        • 2016-08-31
        • 1970-01-01
        • 2017-04-22
        • 1970-01-01
        • 1970-01-01
        • 2015-05-23
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多