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 tornado 4.4. HTTPRequest встановив validate_cert = Істинно, тож ви можете встановити помилкове для вирішення цього питання
pan7an

Спробуйте це: questions.get (' example.com ', verify = certifi.where ())
Ней

Відповіді:


460

Проблема, яка виникає, викликана ненадійним сертифікатом SSL.

Як і @dirk, згаданий у попередньому коментарі, найшвидший спосіб виправлення verify=False:

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

Зверніть увагу, що це призведе до того, що сертифікат не буде підтверджений. Це піддасть вашій програмі ризики для безпеки, наприклад, напади "посереднього".

Звичайно, застосувати судження. Як зазначалося в коментарях, це може бути прийнятним для швидких / викидних програм / сценаріїв, але насправді не слід переходити до виробничого програмного забезпечення .

Якщо просто пропуск перевірки сертифіката не прийнятний у вашому конкретному контексті, врахуйте наступні параметри, найкращим варіантом є встановлення verifyпараметра на рядок, який є шлях до .pemфайлу сертифіката (який ви повинні отримати якоюсь захищеною засоби).

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

  • True: призводить до того, що сертифікат перевіряється у відповідності з власними довіреними органами сертифікатів бібліотеки (Примітка. Ви можете побачити, які запити кореневих сертифікатів використовуються через бібліотеку Certifi, довірну базу даних РЦ, витягнуту з запитів: Certifi - база даних довіри для людей ).
  • False: Обходить перевірку сертифіката повністю .
  • Шлях до файлу CA_BUNDLE для запитів, які використовуються для перевірки сертифікатів.

Джерело: Запити - SSL Cert Verification

Також подивіться на certпараметр за тим же посиланням.


1
Так, коли я використовував dotCloud в ubuntu, вийшов той самий "перевірка сертифіката не вдався". Після змінення "request.session (headers = headers, hooks = hooks, verify = False)" у "/usr/local/lib/python2.6/dist-packages/dotcloud/client/client.py", воно спрацювало.
диїзм

2
Це не позначено як правильне, але я можу переконатися, що воно працює (на відміну від відповідей нижче).
khalid13

40
@ khalid13: Сокира "працює" як ліки від головного болю (немає голови - немає головного болю). Це не означає, що корисно використовувати це саме так. verify=Falseвідключає перевірку SSL-сертифіката хоста.
jfs

24
@JFSebastian Чесно кажучи, це залежить від того, що ти робиш. Для мого швидкого / викидного додатку це було більш ніж достатньо.
khalid13

5
@diyism внесення таких змін звучить дуже небезпечно ...
binki

111

З запитів документації на перевірку SSL :

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

>>> 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 = Неправдиво, якщо ви не хочете підтверджувати сертифікат, якщо у вас є сертифікат, який підписався самостійно
Дірк

16
Якщо у вас є самопідписаний сертифікат, завантажте його та встановіть підтвердження його імені файлу. Немає жодного виправдання для встановлення verify = Неправильно. verify = '/ path / to / cert.pem'
Маттіас Урліхс

14
Вибачте, Boud, мені потрібно було проголосувати за цю відповідь, оскільки запити не обробляють 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, який може не мати ЦА, який підписав ваш серверний сертифікат.


12
@ 9emE0iL18gxCqLT: чому ви вважаєте, що всі системи використовують шлях, який ви надали? requestsможе бути упакований для вашого розповсюдження. Біжи, python -mrequests.certsщоб дізнатися, куди це вказує.
jfs

3
Якщо пакет Cacert запиту Python застарів, як я його оновлюю?
CMCDragonkai

5
Ви не повинні використовувати це cacert.pemз curl. Він містить багато відкликаних сертів. Ознайомтесь із Certifi (використовує запити): certifi.io
Кеннет Рейц

3
@KennethReitz: 1– що запити використовують невдачі для ОП (інакше питання не виникло) 2– cacert.pemце сертифікати CA, вилучені з Mozilla (за допомогою CURL) - це лише приклад (якщо список CA використовується популярною веб-сторінкою -browser не може бути використаний як приклад, тоді я не знаю, що може бути) - пункт відповіді, що ви можете передавати свій власний файл CA, якщо список за замовчуванням не вдається.
jfs

Чи можете ви це зробити і одночасно використовувати сертифікати клієнта? У мене виникають проблеми з цим.
користувач1156544

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 cert або відключити перевірку сертифікатів, але глобально в навколишньому середовищі, не редагуючи вихідний код? Наприклад, якщо я завантажую наявні утиліти Python (наприклад, AWS CLI) і хочу довіряти certs або ігнорувати перевірку сертифікатів для цих інструментів?
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-файлу. Тепер це працює!
mallyvai

Дякую, те саме питання було з відкритим Fiddler
користувачем565447

@ user565447 Я намагаюся зараз це працювати з Fiddler. Чи має налаштування REQUESTS_CA_BUNDLE для роботи Fiddler's cert?
Howiecamp

19

Якщо у вас є бібліотека, на яку покладається, requestsі ви не можете змінити шлях підтвердження (як, наприклад, pyvmomi), вам доведеться знайти в cacert.pemкомплекті запити та додати свій CA там. Ось загальний підхід до пошуку 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

linux

#  (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

btw. @ request-devs, зв'язування власних кекерів із запитом - це насправді, насправді дратує ... особливо той факт, що, здається, ви не спочатку користуєтесь системним магазином ca, і це ніде не зафіксовано.

оновлення

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

REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-bundle.crt python -c "import requests; requests.get('https://somesite.com';)"

У сто разів це: ключовим є неможливість змінити verifyшлях.
ghukill

Що робити, якщо ви використовуєте підписаний сертифікат? Що було б у цій справі?
користувач1114

Крихітне оновлення - для python 3.6 мають бути круглі дужки для команди print - python -c "імпорт запитів; print (
questions.certs.where

15

Я зіткнувся з тією ж проблемою за допомогою gspread, і ці команди працюють для мене:

sudo pip uninstall -y certifi
sudo pip install certifi==2015.04.28

Це зробило це для мене. Дякую :)
alex-mcleod

4
Це має зворотний бік перевстановлення потенційно відкликаних / ненадійних сертифікатів із старої версії certifi, НЕ рекомендується.
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) створив сертифікат.

EDIT: якщо ви не можете редагувати код (оскільки у вас працює третя програма), ви можете спробувати додати 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:

sudo apt-get install ca-certificates

Оновлення часу також може вирішити це:

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

Якщо ви використовуєте самопідписаний сертифікат, вам, ймовірно, доведеться додати його в систему вручну.


Зауважте, це стосується лише запитів, встановлених через apt-get, який Debian / Ubuntu модифікує для використання системних тертів. Запрошує
Kenneth Reitz

Чи не повинно бути кореневого СА? Для чого потрібні проміжні продукти?
Тіммі

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

Я боровся з цією проблемою за HOURS.

Я намагався оновити запити. Потім я оновив сертифікати. Я вказав на verify.where () (Код все одно робить це за замовчуванням). Нічого не працювало.

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


Якщо ви оновили OpenSSL до версії> 1.0.1, можливо, це було проблемою. Дивіться мою відповідь нижче. stackoverflow.com/a/44543047/1413201
Тім Ludwinski

Перехід від Python 2.7.9 до 2.7.10 зафіксував це для мене.
crazystick

3

Це схоже на відповідь @ rafael-almeida, але я хочу зазначити, що за запитами 2.11+, не verifyможна взяти 3 значення , насправді 4:

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

Решта моєї відповіді стосується №4, як використовувати каталог для підтвердження сертифікатів:

Отримайте необхідні публічні сертифікати та помістіть їх у каталог.

Строго кажучи, ви, ймовірно, повинні "використовувати" позадіапазонний метод отримання сертифікатів, але ви також можете просто завантажити їх за допомогою будь-якого браузера.

Якщо сервер використовує ланцюжок сертифікатів, обов'язково отримуйте кожен сертифікат у ланцюзі.

Згідно з документацією на запити, каталог, що містить сертифікати, спочатку повинен бути оброблений утилітою "повторного перегляду" ( openssl rehash).

(Це вимагає OpenSSL 1.1.1+, і не всі вікна підтримки реалізації OpenSSL переспіви. Якщо openssl rehashне працюватиме для вас, ви можете спробувати запустити рубіновий скрипт переспів на https://github.com/ruby/openssl/blob/master /sample/c_rehash.rb , хоча я цього не пробував.)

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

Ви також можете просто ліниво перебирати:

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/isissue/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. Наведене вище вирішення все-таки виправляє його.
Tamás Szelei

1

Як згадував @Rafael Almeida, проблема, яка виникає, викликана ненадійним сертифікатом SSL. У моєму випадку сертифікат SSL не був довірений моєму серверу. Щоб обійти це без шкоди для безпеки, я завантажив сертифікат і встановив його на сервер (просто двічі клацнувши на .crt файл, а потім встановіть сертифікат ...).


0

Неможливо додати параметри, якщо запити викликаються з іншого пакету. У цьому випадку додавання сертифікатів до пакета cacert - це прямий шлях, наприклад, мені довелося додати "StartCom Class 1 Primary Intermediate Server CA", для якого я завантажив кореневу cert в 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, і не встановлено модуля certifi. Встановлений модуль запитів у версії 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.