Python запрашивает выбрасывание SSLError

350

Я работаю над простым сценарием, который включает в себя CAS, проверку безопасности jspring, перенаправление и т. Д. Я хотел бы использовать запросы Python от Кеннета Рейтца, потому что это отличная работа! Тем не менее, CAS требует проверки через SSL, поэтому мне нужно сначала пройти этот шаг. Я не знаю, чего хотят запросы Python? Где должен находиться этот сертификат SSL?

Traceback (most recent call last):
  File "./test.py", line 24, in <module>
  response = requests.get(url1, headers=headers)
  File "build/bdist.linux-x86_64/egg/requests/api.py", line 52, in get
  File "build/bdist.linux-x86_64/egg/requests/api.py", line 40, in request
  File "build/bdist.linux-x86_64/egg/requests/sessions.py", line 209, in request 
  File "build/bdist.linux-x86_64/egg/requests/models.py", line 624, in send
  File "build/bdist.linux-x86_64/egg/requests/models.py", line 300, in _build_response
  File "build/bdist.linux-x86_64/egg/requests/models.py", line 611, in send
requests.exceptions.SSLError: [Errno 1] _ssl.c:503: error:14090086:SSL routines:SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
TedBurrows
источник
Можете ли вы поделиться информацией о коде? Похоже, что есть пропущенный шаг.
TankorSmash
5
Вы всегда должны указывать версии программного обеспечения, с которыми вам нужна помощь.
Петр Доброгост
Я получил эту проблему, где я использую Python 3.5 Торнадо 4.4. HTTPRequest установил validate_cert = True, чтобы вы могли установить значение False, чтобы справиться с этим
pan7an
Попробуйте это: запросы.get (' example.com ', verify = certifi.where ())
Nei

Ответы:

461

Возникшая проблема связана с ненадежным сертификатом SSL.

Как и @dirk, упомянутый в предыдущем комментарии, самое быстрое исправление - установка verify=False:

requests.get('https://example.com', verify=False)

Обратите внимание, что это приведет к тому, что сертификат не будет проверен. Это подвергнет ваше приложение угрозам безопасности, таким как атаки «человек посередине».

Конечно, применять суждение. Как упоминалось в комментариях, это может быть приемлемо для быстрых / одноразовых приложений / скриптов, но на самом деле не должно переходить на производственное программное обеспечение .

Если просто пропустить проверку сертификата в вашем конкретном контексте недопустимо, рассмотрите следующие варианты, лучше всего установить verifyпараметр в строку, которая является путем к.pem файлу сертификата (который вы должны получить с помощью какого-либо безопасного средства).

Таким образом, начиная с версии 2.0, verifyпараметр принимает следующие значения с соответствующей семантикой:

  • True: проверяет сертификат на соответствие собственным доверенным центрам сертификации библиотеки (Примечание: вы можете увидеть, какие запросы корневых сертификатов используются через библиотеку Certifi, базу данных доверенных сертификатов RC, извлеченную из запросов: Certifi - Trust Database for Humans ).
  • False: Обходит проверку сертификата полностью .
  • Путь к файлу CA_BUNDLE для запросов, используемых для проверки сертификатов.

Источник: Запросы - Проверка SSL сертификата

Также взгляните на certпараметр по той же ссылке.

Рафаэль Алмейда
источник
1
Да, когда я использовал dotCloud в Ubuntu, то же самое "сертификат проверить не удалось" вышел. После изменения файла «request.session (headers = headers, hooks = hooks, verify = false)» в «/usr/local/lib/python2.6/dist-packages/dotcloud/client/client.py» все заработало.
diyism
2
Это не помечено как правильное, но я могу убедиться, что это работает (в отличие от ответов ниже).
khalid13
40
@ khalid13: топор «работает» как лекарство от головной боли (нет головы - нет головной боли). Это не значит, что это хорошая идея - использовать ее таким образом. verify=Falseотключает проверку SSL-сертификата хоста.
JFS
24
@JFSebastian Честно говоря, это зависит от того, что вы делаете. Для моего быстрого / одноразового применения этого было более чем достаточно.
khalid13
5
@ диизм, вносящий такие изменения, звучит очень небезопасно…
Бинки
111

Из запросов документации по проверке SSL :

Запросы могут проверять сертификаты SSL для запросов HTTPS, как веб-браузер. Чтобы проверить SSL-сертификат хоста, вы можете использовать аргумент verify:

>>> requests.get('https://kennethreitz.com', verify=True)

Если вы не хотите подтверждать свой SSL-сертификат, сделайте verify=False

Boud
источник
4
Ну, я добавил verify = True, но все равно получил точно такую ​​же ошибку. Без изменений. Что-то еще должно потребоваться, но не знаю, что это может быть.
TedBurrows
Я полагаю, что теперь я опустился в безумие SSL. Я добавил это к своему начальному get ... get (url1, headers = headers, cert = '/ etc / pki / tls / cert.pem', verify = True, config = my_config) Итак, теперь я получаю эту ошибку. request.exceptions.SSLError: [Errno 336265225] _ssl.c: 351: ошибка: 140B0009: подпрограммы SSL: SSL_CTX_use_PrivateKey_file: PEM lib У меня нет ни малейшего понятия, что это значит.
TedBurrows
14
Просто установите verify = False, если вы не хотите проверять сертификат, а если у вас есть самозаверяющий сертификат
Dirk
16
Если у вас есть самозаверяющий сертификат, загрузите его и установите для проверки имя файла. Нет никаких оправданий для установки verify = False. verify = '/ path / to / cert.pem'
Матиас Урлич
14
Извините, Боуд, мне нужно было проголосовать за этот ответ, поскольку запросы не обрабатывают HTTPS-запросы "как веб-браузер". Если полная цепочка доверия SSL (включая промежуточные сертификаты) не объявлена ​​на сервере и требует дополнительной загрузки сертификата, вы получите вышеуказанную ошибку проверки SSL. Веб-браузеры выполнят дополнительную загрузку и не будут отмечать ошибки сертификата. Это один из способов отличия веб-браузера и запросов. Есть и другие. Запросы выполняет некоторую проверку, но это не так хорошо, как браузер.
Луи Кремен
53

Имя файла CA для использования вы можете передать через verify:

cafile = 'cacert.pem' # http://curl.haxx.se/ca/cacert.pem
r = requests.get(url, verify=cafile)

Если вы используете, verify=Trueто requestsиспользует свой собственный набор CA, который может не иметь CA, который подписал ваш сертификат сервера.

JFS
источник
12
@ 9emE0iL18gxCqLT: почему вы думаете, что все системы используют указанный вами путь? requestsмогут быть упакованы для вашего распространения. Беги, python -mrequests.certsчтобы узнать, куда он указывает.
JFS
3
Если пакет cacert запроса Python устарел, как мне его обновить?
CMCDragonkai
5
Вы не должны использовать это cacert.pemот curl. Он содержит много отозванных сертификатов. Проверьте Certifi (который использует Requests): certifi.io
Кеннет Рейц
3
@KennethReitz: 1 - то, что использует Requests, не срабатывает для OP (иначе не было бы вопроса) 2 cacert.pem- это сертификаты CA, извлеченные из Mozilla (cURL) - это всего лишь пример (если список CA используется популярной сетью) -browser не может быть использован в качестве примера, тогда я не знаю, что может быть) - точка ответа, что вы можете передать свой собственный файл CA, если список по умолчанию не удается.
Jfs
Можете ли вы сделать это и использовать клиентские сертификаты одновременно? У меня проблемы с этим.
user1156544
42

$ pip install -U requests[security]

  • Протестировано на Python 2.7.6 @ Ubuntu 14.04.4 LTS
  • Протестировано на Python 2.7.5 @ MacOSX 10.9.5 (Mavericks)

Когда этот вопрос был открыт (2012-05), версия запросов была 0.13.1. В версии 2.4.1 (2014-09) дополнительные функции безопасности были введены с использованиемcertifi пакет, если он доступен.

Прямо сейчас (2016-09) основной версией является 2.11.1, которая хорошо работает без verify=False . Не нужно использовать requests.get(url, verify=False), если установлено с requests[security]дополнениями.

alanjds
источник
7
фиксируется pip install -U requests[security] --no-cacheдва раза иpip install certifi==2015.04.28
Аамир Абро
@alanjds Что если я захочу либо настроить Python для доверия какому-либо SSL-сертификату, либо отключить проверку сертификата, но глобально в среде, без редактирования исходного кода? Например, если я загружаю существующие утилиты Python (например, CLI AWS) и хочу доверять сертификатам или игнорировать проверку сертификатов для этих инструментов?
Howiecamp
@Howiecamp, тогда вы можете пройти через ответ jf-sebastian, я думаю: stackoverflow.com/a/12865159/798575
alanjds
@alanjds Но разве его ответ не предполагает, что я пишу код и / или имею доступ к коду? Я надеюсь реализовать это на уровне окружающей среды.
Howiecamp
3
сделать pip install --upgrade pipперед установкой пакета безопасности запросов, чтобы избежать других ошибок
Vincent Claes
40

Я столкнулся с той же самой проблемой, и ssl сертификат проверяет проблему с ошибкой при использовании aws boto3, просмотрев код boto3, я обнаружил, что REQUESTS_CA_BUNDLEона не установлена, поэтому я исправил обе проблемы, установив ее вручную:

from boto3.session import Session
import os

# debian
os.environ['REQUESTS_CA_BUNDLE'] = os.path.join(
    '/etc/ssl/certs/',
    'ca-certificates.crt')
# centos
#   'ca-bundle.crt')

Для aws-cli, я полагаю, установка REQUESTS_CA_BUNDLE в ~/.bashrcисправит эту проблему (не проверялось, потому что мой aws-cli работает без него).

REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt # ca-bundle.crt
export REQUESTS_CA_BUNDLE
Yong
источник
2
Это исправило мою проблему! Я использовал Charles Proxy на Mac для отладки библиотеки, которая выполняла вызовы JSON для API-интерфейсов HTTPS. Я установил сертификат Charless, как указано, добавил его в цепочку для ключей, но Python продолжал работать с ошибкой: SSLError: («плохое рукопожатие: ошибка ([(« Подпрограммы SSL »,« ssl3_get_server_certificate »,« проверка сертификата не удалась »)],)" Чтобы исправить это, я в итоге последовал вашему совету о добавлении REQUESTS_CA_BUNDLE и экспорте сертификата Чарльза из моей цепочки для ключей в виде файла .pem. Теперь это работает!
Малливай
Спасибо, такая же проблема была с открытым Fiddler
user565447
@ user565447 Я пытаюсь заставить это работать с Fiddler прямо сейчас. Должна ли установка REQUESTS_CA_BUNDLE для сертификата Fiddler работать?
Howiecamp
19

В случае, если у вас есть библиотека, на которую requestsвы полагаетесь, и вы не можете изменить путь проверки (например, с помощью pyvmomi), вам придется найти cacert.pemпакет с запросами и добавить туда свой ЦС. Вот общий подход к поиску cacert.pemместоположения:

окна

C:\>python -c "import requests; print requests.certs.where()"
c:\Python27\lib\site-packages\requests-2.8.1-py2.7.egg\requests\cacert.pem

линукс

#  (py2.7.5,requests 2.7.0, verify not enforced)
root@host:~/# python -c "import requests; print requests.certs.where()"
/usr/lib/python2.7/dist-packages/certifi/cacert.pem

#  (py2.7.10, verify enforced)
root@host:~/# python -c "import requests; print requests.certs.where()"
/usr/local/lib/python2.7/dist-packages/requests/cacert.pem

Кстати. @ questions-devs, связывание ваших собственных cacerts с запросом действительно очень раздражает ... особенно тот факт, что вы, кажется, не используете систему ca store в первую очередь, и это нигде не задокументировано.

Обновить

в ситуациях, когда вы используете библиотеку и не можете контролировать местоположение ca-bundle, вы также можете явно установить местоположение ca-bundle в качестве вашего ca-bundle для всего хоста:

REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-bundle.crt python -c "import requests; requests.get('https://somesite.com';)"
Тинтин
источник
Сто раз так: ключом является невозможность изменить verifyпуть.
ghukill
Что если вы используете самозаверяющий сертификат? Каким будет CA в этом случае?
user1114
Крошечное обновление - для python 3.6 должны быть круглые скобки для команды печати - python -c "запросы на импорт; печать (
запросы.certs.where
15

Я сталкиваюсь с той же проблемой, используя gspread, и эти команды работают для меня:

sudo pip uninstall -y certifi
sudo pip install certifi==2015.04.28
user941581
источник
Это сделало это для меня. Спасибо :)
alex-mcleod
4
Это имеет обратную сторону переустановки потенциально отозванных / ненадежных сертификатов из более старой версии сертификата, НЕ рекомендуется.
dragon788
если по какой-то причине вы вынуждены придерживаться ранней версии Python 2.7, понижение уровня сертификации является единственным подходом, который сработал для меня
seans
15

Если вы хотите удалить предупреждения, используйте код ниже.

import urllib3

urllib3.disable_warnings()

и verify=Falseс request.getили postметодом

AniketGole
источник
12

Я нашел конкретный подход для решения аналогичной проблемы. Идея заключается в указании файла cacert, хранящегося в системе и используемого другими приложениями на основе ssl.

В Debian (я не уверен, что то же самое в других дистрибутивах) файлы сертификатов (.pem) хранятся в /etc/ssl/certs/Итак, вот код, который работает для меня:

import requests
verify='/etc/ssl/certs/cacert.org.pem'
response = requests.get('https://lists.cacert.org', verify=verify)

Чтобы угадать, какой pemфайл выбрать, я просматриваю URL и проверяю, какой центр сертификации (CA) сгенерировал сертификат.

РЕДАКТИРОВАТЬ: если вы не можете редактировать код (поскольку вы запускаете третье приложение), вы можете попытаться добавить pemсертификат непосредственно /usr/local/lib/python2.7/dist-packages/requests/cacert.pem(например, скопировать его в конец файла).

мел
источник
2
Связанный пост для отладки CA_BUNDLE, используемого Python.
ЧК
Как насчет замены /usr/local/lib/python2.7/dist-packages/requests/cacert.pemсимволической ссылкой на магазин ОС?
CMCDragonkai
8

Если вы не беспокоитесь о сертификате, просто используйте verify=False.

import requests

url = "Write your url here"

returnResponse = requests.get(url, verify=False)
Йогеш Прасад
источник
7

После нескольких часов отладки я смог заставить это работать, используя следующие пакеты:

requests[security]==2.7.0  # not 2.18.1
cryptography==1.9  # not 2.0

с помощью OpenSSL 1.0.2g 1 Mar 2016

Без этих пакетов verify=Falseне работало.

Я надеюсь, что это поможет кому-то.

Майкл
источник
5

Я столкнулся с той же проблемой. Оказывается, я не установил промежуточный сертификат на своем сервере (просто добавьте его в конец вашего сертификата, как показано ниже).

https://www.digicert.com/ssl-support/pem-ssl-creation.htm

Убедитесь, что у вас установлен пакет ca-Certificates:

sudo apt-get install ca-certificates

Обновление времени также может решить эту проблему:

sudo apt-get install ntpdate
sudo ntpdate -u ntp.ubuntu.com

Если вы используете самозаверяющий сертификат, вам, вероятно, придется добавить его в вашу систему вручную.

Мариус Крачиуною
источник
Обратите внимание, это относится только к установкам запросов через apt-get, который был изменен Debian / Ubuntu для использования системных сертификатов. Запрашивает правильные корабли со своим собственным тщательно отобранным пакетом CA: certifi.io
Кеннет Рейтц
Разве корневого ЦС недостаточно? Зачем вам нужны промежуточные продукты?
Тимми
5

Если вызовы запросов скрыты где-то глубоко в коде, и вы не хотите устанавливать сертификат сервера, то только для целей отладки можно выполнить запросы monkeypatch:

import requests.api
import warnings


def requestspatch(method, url, **kwargs):
    kwargs['verify'] = False
    return _origcall(method, url, **kwargs)

_origcall = requests.api.request
requests.api.request = requestspatch
warnings.warn('Patched requests: SSL verification disabled!')

Никогда не используйте в производстве!

xmedeko
источник
4

Я полагаю, слишком поздно для вечеринки, но я хотел вставить исправление для таких странников, как я! Поэтому на Python 3.7.x у меня сложилось следующее

Введите следующее в вашем терминале

pip install --upgrade certifi      # hold your breath..

Попробуйте запустить ваш скрипт / запросы еще раз и посмотрите, работает ли он (я уверен, что он еще не будет исправлен!). Если это не сработало, попробуйте запустить следующую команду в терминале напрямую.

open /Applications/Python\ 3.6/Install\ Certificates.command  # please replace 3.6 here with your suitable python version
д-кодер
источник
3

Я боролся с этой проблемой в течение ЧАСОВ.

Я пытался обновить запросы. Затем я обновил сертификат. Я указал check to certifi.where () (код делает это по умолчанию в любом случае). Ничего не получалось.

Наконец я обновил свою версию Python до Python 2.7.11. Я был на Python 2.7.5, у которого были некоторые несовместимости с способом проверки сертификатов. Как только я обновил Python (и несколько других зависимостей), он начал работать.

ajon
источник
Если вы обновили OpenSSL до версии> 1.0.1, возможно, это была проблема. Смотрите мой ответ ниже. stackoverflow.com/a/44543047/1413201
Тим Людвински
Переход с Python 2.7.9 на 2.7.10 исправил это для меня.
crazystick
3

Это похоже на ответ @ rafael-almeida, но я хочу отметить, что по состоянию на запросы 2.11+ нет 3-х значений, которые verifyможно принять, на самом деле 4:

  • True: проверяет соответствие внутренних доверенных ЦС запросов.
  • False: Обходит проверку сертификата полностью . (Не рекомендуется)
  • Путь к файлу CA_BUNDLE. запросы будут использовать это для проверки сертификатов сервера.
  • Путь к каталогу, содержащему открытые файлы сертификатов. запросы будут использовать это для проверки сертификатов сервера.

Остальная часть моего ответа о # 4, как использовать каталог, содержащий сертификаты для проверки:

Получите необходимые публичные сертификаты и поместите их в каталог.

Строго говоря, вы, вероятно, «должны» использовать внеполосный метод получения сертификатов, но вы также можете просто загрузить их с помощью любого браузера.

Если сервер использует цепочку сертификатов, обязательно получите каждый отдельный сертификат в цепочке.

Согласно документации по запросам, каталог, содержащий сертификаты, должен сначала обрабатываться утилитой rehash (openssl rehash ).

(Для этого требуется openssl 1.1.1+, и не все реализации Windows openssl поддерживают перефразирование. Если у openssl rehashвас не получится, вы можете попробовать запустить скрипт rehash ruby ​​по адресу https://github.com/ruby/openssl/blob/master. /sample/c_rehash.rb , хотя я этого не пробовал.)

У меня были некоторые проблемы с получением запросов на распознавание моих сертификатов, но после того, как я использовал openssl x509 -outform PEM команду для преобразования сертификатов в .pemформат Base64 , все работало отлично.

Вы также можете просто сделать ленивую перефразировку:

try:
    # As long as the certificates in the certs directory are in the OS's certificate store, `verify=True` is fine.
    return requests.get(url, auth=auth, verify=True)
except requests.exceptions.SSLError:
    subprocess.run(f"openssl rehash -compat -v my_certs_dir", shell=True, check=True)
    return requests.get(url, auth=auth, verify="my_certs_dir")
cowlinator
источник
2

В настоящее время существует проблема в модуле запросов, вызывающая эту ошибку, которая присутствует в версиях от v2.6.2 до v2.12.4 (ATOW): https://github.com/kennethreitz/requests/issues/2573

Обойти эту проблему можно, добавив следующую строку: requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS = 'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS'

Питер
источник
FWIW, он все еще присутствует с запросами == 2.13.0. Вышеуказанный обходной путь исправляет это все еще.
Тамас Селеи
1

Как упомянул @Rafael Almeida, проблема, с которой вы столкнулись, вызвана ненадежным сертификатом SSL. В моем случае SSL-сертификат не был доверен моему серверу. Чтобы обойти это без ущерба для безопасности, я скачал сертификат и установил его на сервере (просто дважды щелкнув файл .crt, а затем установите сертификат ...).

Майкл
источник
0

Невозможно добавить опции, если запросы вызываются из другого пакета. В этом случае добавление сертификатов в пакет cacert является прямым путем, например, мне пришлось добавить «Первичный промежуточный сервер CA класса StartCom Class 1», для которого я загрузил корневой сертификат в StartComClass1.pem. учитывая, что мой virtualenv называется caldav, я добавил сертификат с:

cat StartComClass1.pem >> .virtualenvs/caldav/lib/python2.7/site-packages/pip/_vendor/requests/cacert.pem
cat temp/StartComClass1.pem >> .virtualenvs/caldav/lib/python2.7/site-packages/requests/cacert.pem

одного из тех может хватить, я не проверял

rhoerbe
источник
0

У меня была похожая или та же проблема сертификации. Я читал, что версии OpenSSL менее 1.0.2, запросы которых зависят от того, иногда возникают проблемы при проверке надежных сертификатов (см. Здесь ). Кажется, что CentOS 7 использует 1.0.1e, которая, похоже, имеет проблему.

Я не был уверен, как обойти эту проблему в CentOS, поэтому я решил разрешить более слабые 1024-битные сертификаты CA.

import certifi # This should be already installed as a dependency of 'requests'
requests.get("https://example.com", verify=certifi.old_where())
Тим Людвински
источник
Я использую Python 2.7.10, установленный ArcGIS, и модуль сертификации не установлен. Модуль запросов установлен в версии 2.11.1.
Лукас
0

Мне пришлось обновить с Python 3.4.0 до 3.4.6

pyenv virtualenv 3.4.6 myvenv
pyenv activate myvenv
pip install -r requirements.txt
Павел
источник
0

В моем случае причина была довольно тривиальной.

Я знал, что проверка SSL работала несколько дней назад и фактически работала на другом компьютере.

Следующим моим шагом было сравнение содержимого и размера сертификата между машиной, на которой работала проверка, и той, на которой она не работала.

Это быстро привело меня к определению, что сертификат на «неправильно» работающей машине не был хорош, и как только я заменил его на «хороший» сертификат, все было хорошо.

mastDrinkNimbuPani
источник