- Решение ужасных проблем с сертификатами в модуле Python Requests
- Проблема
- Попытки
- Выполнение незащищенных вызовов с verify=false
- Предоставить сертификат сервера
- Переопределить CA_REQUESTS_BUNDLE
- Преобразовать в другую кодировку сертификата
- Назад к основам
- Решение
- ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1056)
Решение ужасных проблем с сертификатами в модуле Python Requests
Недавно я работал с модулем запросов Python для защиты вызова API с использованием сертификата сервера.
n Я застрял на одном месте, и узнать, что я сделал, чтобы исправить эту проблему, было здорово, и это побудило меня создать сообщение на глубокий анализ SSL-сертификатов.
Проблема
Я использовал модуль запросов, и вот вызов API.
response = requests.post(url, files=files, headers=headers)
Это ошибка, которую я получил в ответ:
/ (Caused by SSLError(SSLCertVerification(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1108)'))
Попытки
Выполнение незащищенных вызовов с verify=false
Моей первой попыткой было использовать флаг подтверждения как False и попробовать.
response = requests.post(url, files=files, headers=headers, verify=False)
Хотя я получил 200, я получил неприятное предупреждение, подтверждающее, что я делаю ужасную работу, не предоставляя сертификат. Поэтому мне нужно было найти правильный способ сделать это.
Предоставить сертификат сервера
Сначала я подумал, что если я смогу указать сертификат сервера в ключе проверки, это поможет. Так я и сделал,
response = requests.post(url, files=files, headers=headers, verify='server.cer')
Это сертификат с кодировкой DER
Я получил еще одну ошибку:
/ (Caused by SSLError(SSLError(136, '[X509] no certificate or crl found (_ssl.c:4232)'))
Переопределить CA_REQUESTS_BUNDLE
Модуль запрашивает использование certifi для доступа к пакету ЦС и проверки безопасных соединений SSL, и мы можем использовать переменную среды CA_REQUESTS_BUNDLE для переопределения расположение пакета ЦС. Поэтому я подумал, что если я смогу вручную указать server.cer в этой переменной, я достигну просветления. Но, к моему отчаянию, и это не удалось.
Преобразовать в другую кодировку сертификата
Затем я подумал, что модуль requests не должен принимать сертификат в кодировке DER. Поэтому я преобразовал в PEM, который является открытым текстом, но закодирован в Base 64.
openssl x509 -in server.cer -inform DER -outform PEM -out server.pem
response = requests.post(url, files=files, headers=headers, verify='server.pem')
/ (Caused by SSLError(SSLCertVerification(1, '[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1108)'))
Да, это то же самое, что и Ошибка 1. Итак, мы вернулись к исходной точке. Я пытался поискать в Интернете, но ни у кого не было толкового решения. Кто-то
Тогда я подумал, что это не выход, я решу этот вопрос. Так что я много учился, чтобы получить сертификаты, и, наконец, я их получил. Я написал статью «Глубокое погружение» и поместил туда все.
Назад к основам
Эта проблема и все подобные проблемы, связанные с сертификатами (на любом языке, не только на python) в Интернете, требуют четкого и ясного понимания цепочки сертификатов. Я очень четко объяснил все в своем посте с глубоким погружением.
Обычно цепочка сертификатов состоит из трех сторон.
- Корневой центр сертификации
- Один или несколько промежуточных центров сертификации
- Сертификат сервера запрашивает подпись сертификата.
Знаки корневого ЦС → промежуточный ЦС
Промежуточные знаки ЦС → сертификат сервера
Корневые сертификаты от корневых ЦС обычно имеют очень долгий срок действия (более 20 лет) и поставляются в виде пакетов ЦС на всех компьютерах и серверах и хранятся очень и очень надежно в соответствии со строгими правилами, чтобы никто не мог изменить их на любой машине. .
Поскольку корневой ЦС очень и очень священн, им нужны промежуточные ЦС, чтобы делегировать ответственность за подписание сертификата сервера, когда кто-либо запрашивает его, предоставляя CSR. Эти посредники называются промежуточными ЦС. В цепочке сертификатов может быть несколько промежуточных ЦС.
Решение
В нашем случае, когда мы конвертировали файл сертификата в формат PEM, мы делаем ошибку,
unable to get local issuer certificate (_ssl.c:1108)
Это происходит по 2 причинам:
- Сертификат промежуточного ЦС недоступен в файле server.pem
- Поскольку мы вручную указываем, какой файл сертификата использовать, указав verify=server.pem*,*, модуль запроса python не будет использовать уже существующий пакет ЦС, скорее будет использовать сервер . pem и ожидает, что он содержит все сертификаты в цепочке, server.cer, промежуточный сертификат и корневой сертификат
Поэтому я вручную удалил сертификат сервера следующим образом:
Это делается в Windows, но то же самое можно сделать и в Mac или Linux.
После удаления всех сертификатов из server.cer у нас будут разные файлы .cer для всех ЦС. Таким образом, для приведенного выше случая у нас будет 4 файла .cer.
- Корневой центр сертификации (Zeescalar root ca)
- Промежуточный ЦС 1 (Zscalar промежуточный корневой ЦС)
- Промежуточный ЦС 2 (Zscalar промежуточный корневой ЦС)
- файл .cer сервера Google
Теперь все, что нам нужно сделать, это преобразовать все эти файлы .cer в файлы .pem и объединить их вместе, чтобы создать объединенный файл pem файл и передайте его запросам Python.
Таким образом, для всех файлов cer выполните следующую команду 4 раза.
openssl x509 -in server.cer -inform DER -outform PEM >> consolidate.pem
Всё, что мы здесь делаем, — это создаём полноценный пакет ЦС со всеми сертификатами, и в любом случае мы можем это сделать, это нормально.
Вот и все, мы передаем наш новый файл CA pem запросам python, и он счастлив.
response = requests.post(url, files=files, headers=headers, verify='consolidate.pem')Response [200]>
. информация Также опубликовано здесь.
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1056)
I am using Python 3.7.3 to run a GET request to a PHP file hosted on my website. However, when I run it I receive the error below. I have installed requests through pip3 on Homebrew. I am using macOS Mojave.
Traceback (most recent call last):
File «/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/urllib3/connectionpool.py», line 600, in urlopen chunked=chunked)
File «/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/urllib3/connectionpool.py», line 343, in _make_request self._validate_conn(conn)
File «/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/urllib3/connectionpool.py», line 839, in _validate_conn conn.connect()
File «/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/urllib3/connection.py», line 344, in connect ssl_context=context)
File «/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/urllib3/util/ssl_.py», line 344, in ssl_wrap_socket
return context.wrap_socket(sock, server_hostname=server_hostname)
File «/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/ssl.py», line 412, in wrap_socket session=session
File «/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/ssl.py», line 853, in _create self.do_handshake()
File «/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/ssl.py», line 1117, in do_handshake self._sslobj.do_handshake()
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1056) During handling of the above exception, another exception occurred: Traceback (most recent call last):
File «/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/requests/adapters.py», line 449, in send timeout=timeout
File «/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/urllib3/connectionpool.py», line 638, in urlopen _stacktrace=sys.exc_info()[2])
File «/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/urllib3/util/retry.py», line 398, in increment raise MaxRetryError(_pool, url, error or ResponseError(cause)) urllib3.exceptions.MaxRetryError: HTTPSConnectionPool(host=’ijetlab.com’, port=443): Max retries exceeded with url: /api/api.php?one=1&two=2 (Caused by SSLError(SSLCertVerificationError(1, ‘[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1056)’))) During handling of the above exception, another exception occurred: Traceback (most recent call last):
File «/Users/maxwellnewberry/Documents/test.py», line 12, in r = requests.get(url = URL, params = PARAMS)
File «/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/requests/api.py», line 75, in get return request(‘get’, url, params=params, **kwargs)
File «/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/requests/api.py», line 60, in request return session.request(method=method, url=url, **kwargs)
File «/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/requests/sessions.py», line 533, in request resp = self.send(prep, **send_kwargs)
File «/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/requests/sessions.py», line 646, in send r = adapter.send(request, **kwargs)
File «/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/requests/adapters.py», line 514, in send raise SSLError(e, request=request) requests.exceptions.SSLError: HTTPSConnectionPool(host=’ijetlab.com’, port=443): Max retries exceeded with url: /api/api.php?one=1&two=2 (Caused by SSLError(SSLCertVerificationError(1, ‘[SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1056)’)))
# importing the requests library import requests # api-endpoint URL = "https://ijetlab.com/api/api.php" # defining a params dict for the parameters to be sent to the API PARAMS = # sending get request and saving the response as response object r = requests.get(url = URL, params = PARAMS) # extracting data in json format data = r.json() print(data['response'])
All searches have told me to run ‘Install Certificates.command’, and I have – about 100 times. I have also made the customer install certificates as well.