Ошибка urllib и "SSL: CERTIFICATE_VERIFY_FAILED"
Я получаю следующую ошибку:
Exception in thread Thread-3:
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py", line 810, in __bootstrap_inner
self.run()
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py", line 763, in run
self.__target(*self.__args, **self.__kwargs)
File "/Users/Matthew/Desktop/Skypebot 2.0/bot.py", line 271, in process
info = urllib2.urlopen(req).read()
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", line 154, in urlopen
return opener.open(url, data, timeout)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", line 431, in open
response = self._open(req, data)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", line 449, in _open
'_open', req)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", line 409, in _call_chain
result = func(*args)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", line 1240, in https_open
context=self._context)
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/urllib2.py", line 1197, in do_open
raise URLError(err)
URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:581)>
Это код, который вызывает эту ошибку:
if input.startswith("!web"):
input = input.replace("!web ", "")
url = "https://domainsearch.p.mashape.com/index.php?name=" + input
req = urllib2.Request(url, headers={ 'X-Mashape-Key': 'XXXXXXXXXXXXXXXXXXXX' })
info = urllib2.urlopen(req).read()
Message.Chat.SendMessage ("" + info)
API, который я использую, требует, чтобы я использовал HTTPS. Как я могу заставить его обойти проверку?
Переведено автоматически
Ответ 1
Это не решение вашей конкретной проблемы, но я размещаю ее здесь, потому что эта тема является лучшим результатом Google для "SSL: CERTIFICATE_VERIFY_FAILED", и это навело меня на мысль.
Если вы установили Python 3.6 в OSX и получаете ошибку "SSL: CERTIFICATE_VERIFY_FAILED" при попытке подключиться к сайту https: //, вероятно, это связано с тем, что Python 3.6 в OSX вообще не имеет сертификатов и не может проверять какие-либо SSL-соединения. Это изменение для версии 3.6 в OSX, и для него требуется этап после установки, который устанавливает certifi
пакет сертификатов. Это задокументировано в файле ReadMe.rtf, который вы можете найти по адресу /Applications/Python\ 3.6/ReadMe.rtf
(смотрите также файл Conclusion.rtf и скрипт build-installer.py
, который генерирует установщик macOS).
ReadMe заставит вас запустить скрипт после установки по адресу
/Applications/Python\ 3.10/Install\ Certificates.command
(Приложение терминала, только эта команда должна устранить проблему. Обязательно обновите путь к файлу, используя текущую subversion.)
(ее источником является install_certificates.command
), которая:
- сначала устанавливается пакет Python
certifi
, и - затем создает символическую ссылку из файла сертификатов OpenSSL на файл сертификатов, установленный пакетом
certifi
.
В примечаниях к выпуску есть дополнительная информация: https://www.python.org/downloads/release/python-360 /
В более новых версиях Python есть дополнительная документация по этому поводу:
- https://github.com/python/cpython/blob/e05a703848473b0365886dcc593cbddc46609f29/Mac/BuildScript/resources/ReadMe.rtf#L22-L34
- https://github.com/python/cpython/blob/e05a703848473b0365886dcc593cbddc46609f29/Mac/BuildScript/resources/Conclusion.rtf#L15-L19
- https://github.com/python/cpython/blob/e05a703848473b0365886dcc593cbddc46609f29/Mac/BuildScript/resources/Welcome.rtf#L23-L25
- https://github.com/python/cpython/blob/e05a703848473b0365886dcc593cbddc46609f29/Mac/BuildScript/resources/install_certificates.command
- https://github.com/python/cpython/blob/e05a703848473b0365886dcc593cbddc46609f29/Mac/BuildScript/README.rst
- https://github.com/python/cpython/blob/e05a703848473b0365886dcc593cbddc46609f29/Mac/BuildScript/build-installer.py#L239-L246
Ответ 2
Если вы просто хотите обойти проверку, вы можете создать новый SSLContext. По умолчанию во вновь созданных контекстах используется CERT_NONE.
Будьте осторожны с этим, как указано в разделе 17.3.7.2.1
При непосредственном вызове конструктора SSLContext по умолчанию используется CERT_NONE . Поскольку он не аутентифицирует другой одноранговый узел, он может быть небезопасным, особенно в клиентском режиме, где большую часть времени вы хотели бы убедиться в подлинности сервера, с которым вы разговариваете. Поэтому в клиентском режиме настоятельно рекомендуется использовать CERT_REQUIRED .
Но если вы просто хотите, чтобы это заработало сейчас по какой-то другой причине, вы можете сделать следующее, вам также придется import ssl
:
input = input.replace("!web ", "")
url = "https://domainsearch.p.mashape.com/index.php?name=" + input
req = urllib2.Request(url, headers={ 'X-Mashape-Key': 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' })
gcontext = ssl.SSLContext() # Only for gangstars
info = urllib2.urlopen(req, context=gcontext).read()
Message.Chat.SendMessage ("" + info)
Это должно решить вашу проблему, но на самом деле вы не решаете ни одну из проблем, но вы не увидите [SSL: CERTIFICATE_VERIFY_FAILED]
потому что вы сейчас не проверяете сертификат!
В дополнение к вышесказанному, если вы хотите узнать больше о том, почему вы видите эти проблемы, вам стоит взглянуть на PEP 476 .
В этом PEP предлагается включить проверку подписей сертификата X509, а также проверку имени хоста для HTTP-клиентов Python по умолчанию при условии отказа для каждого вызова. Это изменение будет применено к Python 2.7, Python 3.4 и Python 3.5.
Рекомендуется отказаться, который не отличается от моего совета выше:
import ssl
# This restores the same behavior as before.
context = ssl._create_unverified_context()
urllib.urlopen("https://no-valid-cert", context=context)
В нем также есть крайне нежелательный вариант через monkeypatching, который вы не часто видите в python:
import ssl
ssl._create_default_https_context = ssl._create_unverified_context
Которая переопределяет функцию по умолчанию для создания контекста функцией для создания непроверенного контекста.
Пожалуйста, обратите внимание на это, как указано в PEP:
Это руководство предназначено в первую очередь системным администраторам, которые хотят внедрить более новые версии Python, реализующие этот PEP в устаревших средах, которые еще не поддерживают проверку сертификатов при HTTPS-соединениях. Например, администратор может отказаться от использования, добавив monkeypatch выше в sitecustomize.py в своей стандартной операционной среде для Python. Приложениям и библиотекам НЕ СЛЕДУЕТ широко использовать этот процесс изменения (за исключением, возможно, реакции на настройки конфигурации, контролируемые системным администратором).
Если вы хотите прочитать статью о том, почему не проверять сертификаты плохо в программном обеспечении, вы можете найти ее здесь!
Ответ 3
Подробнее об ответе Крейга Гленни:
в Python 3.6.1 на macOS Sierra
Ввод этого параметра в терминал bash решил проблему:
pip install certifi
/Applications/Python\ 3.6/Install\ Certificates.command
Ответ 4
В Windows Python не просматривает системный сертификат, он использует свой собственный, расположенный по адресу ?\lib\site-packages\certifi\cacert.pem
.
Решение вашей проблемы:
- загрузите сертификат проверки домена в виде файла *.crt или * pem
- откройте файл в редакторе и скопируйте его содержимое в буфер обмена
- найдите свое
cacert.pem
местоположение:from requests.utils import DEFAULT_CA_BUNDLE_PATH; print(DEFAULT_CA_BUNDLE_PATH)
- отредактируйте
cacert.pem
файл и вставьте сертификат проверки вашего домена в конец файла. - Сохраните файл и наслаждайтесь запросами!