簡體   English   中英

如何通過 smtplib (TSL) 接受來自電子郵件服務器的自簽名證書?

[英]How to accept self-signed certificate from e-mail server via smtplib (TSL)?

我的劇本

from stmplib import SMTP
con = SMTP(server, port)
con.starttls()
con.login(user, pass)
con.quit()

出現錯誤: python2.7/ssl.py", line 847, in do_handshake self._sslobj.do_handshake()

當我向該服務器運行命令openssl時,它會出現錯誤 21: Verify return code: 21 (unable to verify the first certificate)

我想知道如何在 python 選項的 smtplib 中指定“通過 tls 建立到電子郵件服務器的連接時始終接受自簽名證書”?就像我在requests.get中設置密鑰verify=False一樣。

使用自定義 smtp class 和context = ssl._create_unverified_context()更新此變體返回與上述相同的錯誤:

import smtplib
import ssl

class MySMTP(smtplib.SMTP):
    def __init__(self, host='', port=0, timeout=5):
        smtplib.SMTP.__init__(self, host, port, timeout=timeout)
        self._host = host

    def starttls(self, keyfile=None, certfile=None, context=None):
        from urllib import _have_ssl

        self.ehlo_or_helo_if_needed()
        if not self.has_extn("starttls"):
            raise SMTPNotSupportedError("STARTTLS extension not supported by server.")
        (resp, reply) = self.docmd("STARTTLS")
        if resp == 220:
            if not _have_ssl:
                raise RuntimeError("No SSL support included in this Python")
            if context is not None and keyfile is not None:
                raise ValueError("context and keyfile arguments are mutually "
                             "exclusive")
            if context is not None and certfile is not None:
                raise ValueError("context and certfile arguments are mutually "
                             "exclusive")
            if context is None:
                context = ssl._create_stdlib_context(certfile=certfile,
                                                 keyfile=keyfile)
            self.sock = context.wrap_socket(self.sock,
                                        server_hostname=self._host)
            self.file = None
            # RFC 3207:
            # The client MUST discard any knowledge obtained from
            # the server, such as the list of SMTP service extensions,
            # which was not obtained from the TLS negotiation itself.
            self.helo_resp = None
            self.ehlo_resp = None
            self.esmtp_features = {}
            self.does_esmtp = 0
        return (resp, reply)

con= MySMTP(server, port)
context  = ssl._create_unverified_context()
con.starttls(context = context)
con.login(user, pass)
con.quit()

遲到的答案,但我修復了ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:852) on python 3.7使用ssl._create_unverified_context() ,即:

import smtplib, ssl
context = ssl._create_unverified_context()
with smtplib.SMTP_SSL("domain.tld", 465, context=context) as server:
    server.login(user, password)
    server.sendmail(sender_email, receiver_email, message.as_string())

看起來你的子類化SMTP類和覆蓋starttls()方法來接受context參數的方法是要走的路 - 它實際上甚至在 Python 3.x 中引入。

然而:

con = MySMTP(server, port)
context  = ssl.create_default_context(cafile=PATH_TO_CERTIFICATE_AUTHORITY_ROOT_CRT_FILE)
con.starttls(context=context)
con.login(user, pass)
con.quit()

應該工作而不是未經驗證的上下文。

當您自簽名證書時,您使用了自己的證書頒發機構,因此您之前可能創建了根 CA 證書。

您的 SMTP 客戶端必須知道此根證書才能驗證您的 SMTP 服務器證書。
因此,找到該文件,將其放在您的 SMTP 客戶端可以訪問的位置,並將此路徑設置為PATH_TO_CERTIFICATE_AUTHORITY_ROOT_CRT_FILE的值。

你做的是:

ssl._create_stdlib_context(certfile=certfile, keyfile=keyfile)

但是certfilekeyfile是客戶端證書和密鑰 - 有些服務器不會接受來自未經驗證的客戶端的連接。

有用的鏈接:
ssl.create_default_context() 文檔
如果您找不到根證書,您可以從頭開始(只需忽略圖片上的所有 MacOS 窗口 - 您的 SMTP 客戶端想要訪問根證書文件 - 他們在本指南中添加到瀏覽器的文件)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM