Python 证书错误:主机名不匹配

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/28768530/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 03:43:08  来源:igfitidea点击:

CertificateError: hostname doesn't match

pythonsslmechanizemechanize-python

提问by pugmastaflex

I'm using a proxy (behind corporate firewall), to login to an https domain. The SSL handshake doesn't seem to be going well:

我正在使用代理(在公司防火墙后面)登录到 https 域。SSL 握手似乎并不顺利:

CertificateError: hostname 'ats.finra.org:443' doesn't match 'ats.finra.org' 

I'm using Python 2.7.9 - Mechanize and I've gotten past all of the login, password, security questioon screens, but it is getting hung up on the certification.

我正在使用 Python 2.7.9 - Mechanize 并且我已经通过了所有的登录、密码、安全问题屏幕,但它被挂在了认证上。

Any help would be amazing. I've tried the monkeywrench found here: Forcing Mechanize to use SSLv3

任何帮助将是惊人的。我试过在这里找到的monkeywrench:Forcing Mechanize to use SSLv3

Doesn't work for my code though.

虽然不适用于我的代码。

If you want the code file I'd be happy to send.

如果您想要代码文件,我很乐意发送。

回答by stvs

This bug in ssl.math_hostname appears in v2.7.9 (it's not in 2.7.5), and has to do with not stripping out the hostname from the hostname:port syntax. The following rewrite of ssl.match_hostname fixes the bug. Put this before your mechanize code:

ssl.math_hostname 中的这个错误出现在 v2.7.9(它不在 2.7.5 中),并且与没有从 hostname:port 语法中剥离主机名有关。以下对 ssl.match_hostname 的重写修复了该错误。把它放在你的机械化代码之前:

import functools, re, urlparse
import ssl

old_match_hostname = ssl.match_hostname

@functools.wraps(old_match_hostname)
def match_hostname_bugfix_ssl_py_2_7_9(cert, hostname):
    m = re.search(r':\d+$',hostname)  # hostname:port
    if m is not None:
        o = urlparse.urlparse('https://' + hostname)
        hostname = o.hostname
    old_match_hostname(cert, hostname)

ssl.match_hostname = match_hostname_bugfix_ssl_py_2_7_9

The following mechanize code should now work:

以下机械化代码现在应该可以工作:

import mechanize
import cookielib

br = mechanize.Browser()

# Cookie Jar
cj = cookielib.LWPCookieJar()
br.set_cookiejar(cj)

# Browser options
br.set_handle_equiv(True)
br.set_handle_gzip(True)
br.set_handle_redirect(True)
br.set_handle_referer(True)
br.set_handle_robots(False)

# Follows refresh 0 but not hang on refresh > 0
br.set_handle_refresh(mechanize._http.HTTPRefreshProcessor(), max_time=1)

br.addheaders = [('User-Agent', 'Nutscrape 1.0')]
# Use this proxy
br.set_proxies({"http": "localhost:3128", "https": "localhost:3128"})
r = br.open('https://www.duckduckgo.com:443/')
html = br.response().read()
# Examine the html response from a browser
f = open('foo.html','w')
f.write(html)
f.close()

回答by hoju

You can avoid this error by monkey patching ssl:

您可以通过猴子修补 ssl 来避免此错误:

import ssl
ssl.match_hostname = lambda cert, hostname: True

回答by fabiomaia

In my case the certificate's DNS name was ::1(for local testing purposes) and hostname verification failed with

在我的情况下,证书的 DNS 名称是::1(用于本地测试目的)并且主机名验证失败

ssl.CertificateError: hostname '::1' doesn't match '::1'

To fix it somewhat properly I monkey patched ssl.match_hostnamewith

为了稍微正确地修复它,我猴子修补ssl.match_hostname

import ssl                                                                                                                                                                                             
ssl.match_hostname = lambda cert, hostname: hostname == cert['subjectAltName'][0][1]

Which actually checks if the hostnames match.

这实际上检查主机名是否匹配。