Вопрос-Ответ

urllib and "SSL: CERTIFICATE_VERIFY_FAILED" Error

Ошибка 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), которая:

В примечаниях к выпуску есть дополнительная информация: https://www.python.org/downloads/release/python-360 /

В более новых версиях Python есть дополнительная документация по этому поводу:

Ответ 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.

Решение вашей проблемы:


  1. загрузите сертификат проверки домена в виде файла *.crt или * pem

  2. откройте файл в редакторе и скопируйте его содержимое в буфер обмена

  3. найдите свое cacert.pem местоположение: from requests.utils import DEFAULT_CA_BUNDLE_PATH; print(DEFAULT_CA_BUNDLE_PATH)

  4. отредактируйте cacert.pem файл и вставьте сертификат проверки вашего домена в конец файла.

  5. Сохраните файл и наслаждайтесь запросами!

python python-2.7