Решение ужасных проблем с сертификатами в модуле Python Requests

Решение ужасных проблем с сертификатами в модуле Python Requests

23 ноября 2022 г.

Недавно я работал с модулем запросов 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) в Интернете, требуют четкого и ясного понимания цепочки сертификатов. Я очень четко объяснил все в своем посте с глубоким погружением.

Обычно цепочка сертификатов состоит из трех сторон.

  1. Корневой центр сертификации
  2. Один или несколько промежуточных центров сертификации
  3. Сертификат сервера запрашивает подпись сертификата.

Делегирование ответственности:

<цитата>

Знаки корневого ЦС → промежуточный ЦС

Промежуточные знаки ЦС → сертификат сервера

Корневые сертификаты от корневых ЦС обычно имеют очень долгий срок действия (более 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]>

:::информация Также опубликовано здесь.

:::


Оригинал