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

Можете ли вы поделиться информацией о коде? Похоже, что есть пропущенный шаг.
— 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


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, который подписал ваш сертификат сервера.


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]дополнениями.


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

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

Это сделало это для меня. Спасибо :)
— alex-mcleod

4
Это имеет обратную сторону переустановки потенциально отозванных / ненадежных сертификатов из более старой версии сертификата, НЕ рекомендуется.
— dragon788

если по какой-то причине вы вынуждены придерживаться ранней версии Python 2.7, понижение уровня сертификации является единственным подходом, который сработал для меня
— seans

15

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

import urllib3

urllib3.disable_warnings()

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


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!')

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


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 (и несколько других зависимостей), он начал работать.


Если вы обновили 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")

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

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


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 работала несколько дней назад и фактически работала на другом компьютере.

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

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.