Подробный гайд по диагностике и устранению ошибки certificate verification failed в Python
Представлен подробный технический гайд по диагностике и устранению ошибки certificate verification failed в Python. Материал структурирован от причин к решениям, с учётом безопасности и современных практик.
Что это за ошибка?
Обычно выглядит так:
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed:
unable to get local issuer certificate (_ssl.c:1002)
Возникает, когда встроенный в Python SSL-модуль не может проверить цепочку доверия сертификата сервера при HTTPS-запросе. Это механизм безопасности, а не баг, но в корпоративных или нестандартных средах он часто блокирует работу.
Основные причины (с подробным разбором)
| № | Причина | Как проявляется |
|---|---|---|
| 1 | Устаревший/отсутствующий набор CA-сертификатов | Python не знает корневые удостоверяющие центры. Часто после чистой установки или в старых версиях Python. |
| 2 | Антивирус или корпоративный Firewall (MITM) | Сеть подменяет сертификат "на лету". Python видит чужой сертификат и отказывается проверять. |
| 3 | Self-signed или просроченный сертификат сервера | Сервер использует тестовый/внутренний сертификат без доверенного CA. |
| 4 | Конфликт OpenSSL / системных хранилищ | Python скомпилирован с одной версией OpenSSL, система использует другую. Или переменные окружения перезаписывают пути. |
| 5 | Неправильная работа с certifi или requests |
Библиотека certifi не обновлена, или код явно передаёт verify=False/неверный путь к CA. |
Пошаговые решения
1. Обновите пакет certifi (базовое решение)
certifi предоставляет современный набор корневых сертификатов.
python -m pip install --upgrade certifi
Проверьте путь к файлу:
import certifi
print(certifi.where()) # Должен вывести путь к .pem файлу
2. Корпоративный антивирус / MITM
Если вы в корпоративной сети, скорее всего трафик инспекцируется.
- Получите корневой сертификат антивируса (обычно
.crtили.pem).
2. Добавьте его в certifi (не рекомендуется править файл напрямую, лучше использовать переменные):
export REQUESTS_CA_BUNDLE="/path/to/your/corporate-ca.pem"
export SSL_CERT_FILE="/path/to/your/corporate-ca.pem"
Для Windows: добавьте в переменные окружения через sysdm.cpl -> Дополнительно -> Переменные среды.
3. Для requests можно указать явно:
import requests
response = requests.get("https://example.com", verify="/path/to/corporate-ca.pem")
3. Self-signed или внутренний сертификат сервера
Важно:
Никогда не используйте verify=False в продакшене. Это открывает дверь для MITM-атак.
Безопасные варианты:
- Установите внутренний CA в систему/
certifi(как в п.2) - Укажите путь к сертификату сервера:
requests.get(url, verify="/path/to/server-cert.pem")
- Для тестов/локальной разработки (только временно!):
import warnings
warnings.filterwarnings('ignore', message='Unverified HTTPS request')
requests.get(url, verify=False)
4. Обновление системных сертификатов
Python зависит от ОС, если не использует certifi.
| ОС | Команда |
|---|---|
| Ubuntu/Debian | sudo apt update && sudo apt install --reinstall ca-certificates && sudo update-ca-certificates |
| RHEL/CentOS/Fedora | sudo dnf reinstall ca-certificates && sudo update-ca-trust |
| macOS | Системные сертификаты обновляются через App Store. Для python.org-установщика запустите: /Applications/Python\ 3.X/Install\ Certificates.command |
| Windows | Убедитесь, что установлены последние обновления Windows. Корпоративные сертификаты часто добавляются через GPO. |
5. Переход на truststore (Python 3.10+)
Современный подход, рекомендованный Python Packaging Authority.
Использует системное хранилище сертификатов вместо certifi.
pip install truststore
import truststore
truststore.inject_into_ssl()
import requests
# Теперь requests использует системные сертификаты ОС
requests.get("https://example.com")
Работает с requests, urllib3, httpx, aiohttp и другими библиотеками на базе ssl.
Диагностика: как быстро найти причину
- Смотрите полный traceback -> ищите
unable to get local issuer certificateилиself signed certificate in certificate chain. - Проверьте сертификат в браузере -> откройте URL, нажмите на значок замка -> "Сертификат". Если браузер ругается -> проблема на сервере/сети.
3. Тест через openssl:
openssl s_client -connect example.com:443 -servername example.com
Ищите Verify return code: 0 (ok). Если другое -> проблема в цепочке.
4. Проверьте переменные окружения:
import os
print(os.environ.get('REQUESTS_CA_BUNDLE'))
print(os.environ.get('SSL_CERT_FILE'))
5. Версия Python и OpenSSL:
import ssl
print(ssl.OPENSSL_VERSION)
Старые OpenSSL (<1.1.1) могут не поддерживать новые алгоритмы подписи.
Лучшие практики
| Не рекомендуется | Рекомендуется |
|---|---|
requests.get(url, verify=False) в продакшене |
Укажите путь к CA: verify='/path/to/ca.pem' |
| Игнорировать ошибку "потому что работает" | Настроить доверенные сертификаты один раз глобально |
Править certifi.where() вручную |
Использовать REQUESTS_CA_BUNDLE или truststore |
Хранить .pem в репозитории с кодом |
Использовать секреты/переменные окружения |
Платформенные особенности
| Платформа | Нюанс |
|---|---|
| macOS (python.org installer) | Требует ручного запуска Install Certificates.command. Homebrew Python использует системные сертификаты автоматически. |
| Windows | certifi работает стабильно. Корпоративные сертификаты добавляются через certutil -addstore root cert.crt. |
| Linux | Полагается на ca-certificates. В контейнерах (Docker) часто отсутствует обновление CA -> добавьте RUN update-ca-certificates в Dockerfile. |
| Docker/Alpine | Используйте apk add ca-certificates или скопируйте .pem в /usr/local/share/ca-certificates/. |
Итог: чек-лист быстрого решения
pip install --upgrade certifi- Проверьте, не блокирует ли трафик антивирус -> добавьте их CA в
REQUESTS_CA_BUNDLE - Для Python 3.10+ попробуйте
truststore.inject_into_ssl() - Никогда не выключайте
verifyв продакшене - Обновите системные CA и OpenSSL
Мы делимся этой технической информацией, чтобы помочь вам в решении задач — используйте её с пониманием. Статья носит рекомендательный характер, поэтому, пожалуйста, применяйте описанные методы осмотрительно.