AppEngine urlfetch validate_certificate = False/Нет, не соблюдается

В AppEngine Developer appserver появляется такая ошибка:

SSLCertificateError: Invalid and/or missing SSL certificate for URL ...

когда я делаю выборку на сервере https с самозаверяющим сертификатом (почти всегда localhost переадресация через ssh на vm):

result = urlfetch.fetch(url=url, method=method, payload=payload,
                        deadline=DEADLINE, validate_certificate=None)

Нельзя ожидать отказов SSL для недействительных сертификатов, где validate_certificate - False, хотя это, возможно, является побочным эффектом политики 2.7.9 в Python, чтобы всегда проверять сертификаты ssl.

Обратите внимание, что передача False (вместо None) для validate_certificate тоже не работает.

Эта проблема возникает на Python 2.7.9-10 через Homebrew/XCode на OS X 10.10.2-4 с AppEngine с 1.9.18 по 1.19.26.

Есть проблемы (например, 12096) об этом в Google App Engine, но я ищу обходной путь.

Вот что я пытался обойти это:

  • Добавить сертификат в цепочку ключей для входа в Mac (работает в браузере, а не с Python)

  • Добавьте сертификат в app-engine-python/lib/cacerts/cacerts.txt и/или ./lib/cacerts/urlfetch_cacerts.txt (хотя для его работы, вероятно, потребуется включить проверку, так как это единственный случай, когда они используются), например,

    $echo → /usr/local/share/app-engine-python/lib/cacerts/urlfetch_cacerts.txt

    $openssl x509 -subject -in server.crt → /usr/local/share/app-engine-python/lib/cacerts/urlfetch_cacerts.txt

  • Отключить HTTP-проверки ssl с помощью PEP-0476 обходной путь i.e.

    ssl._create_default_https_context = ssl._create_unverified_context

    после или после import ssl (вокруг строки 1149) google/appengine/dist27/python_std_lib/httplib.py

Это особенно проблематично для Mac с момента понижения с XCode 7/OS X El Capital больше не является практическим вариантом.

Предпочтительное обходное решение не будет включать в себя обезвреживание исправления кода AppEngine каждый раз при обновлении сервера приложений разработки.


ИЗМЕНИТЬ

Обратите внимание, что встроенные сертификаты OpenSSL, хранящиеся в Mac, хранятся в /System/Library/OpenSSL, который защищен SIP/rootlessness, что, откровенно говоря, является болью для гашения и стоящим чтобы сохранить, если можно.

Я проверил, что сертификат проверяется с помощью openssl s_client -connect localhost:7500 -CAfile server.pem.

Он добавлен в Keychain и в /usr/local/etc/openssl/certs с форматом hash.#, где хеш происходит от openssl x509 -subject_hash -in server.pem (или homebrew ssl, а именно /usr/local/Cellar/openssl/1.0.2d_1/bin/openssl). В этом случае /usr/local/Cellar/openssl/1.0.2d_1/bin/openssl s_client -connect localhost:7500 проверяет сертификат (но python все еще не делает).

Я попытался использовать домашнюю версию python и openssl, но безрезультатно. Выполнение следующего в Python, похоже, всегда терпит неудачу;

./pve/bin/python -c "import requests; requests.get('https://localhost:7500')"

Это также не выполняется, если SSL_CERT_FILE установлен на сертификат сервера (т.е. для дополнительной меры можно ожидать, что он будет работать, поскольку команда openssl по существу работает так), а также не выполняется, если SSL_CERT_PATH установлен на /usr/local/etc/openssl/certs.

Примечание. pve является виртуальным env, где help(ssl) показывает a FILE of /usr/local/Cellar/python/2.7.10_2/Frameworks/Python.framework/Versions/2.7/lib/python2.7/ssl.py

Дальнейшая проверка того, что homebrew Python _ssl.so ссылки на homebrew openssl Я побежал:

xcrun otool -L /usr/local/Cellar/python/ 2.7.10_2/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-dynload/_ssl.so

который возвращает

./подвал/Python/2.7.10_2/Каркасы/Python.framework/Версии/2,7/Library/python2.7/Библиотека-dynload/_ssl.so:

/usr/local/opt/openssl/lib/libssl.1.0.0.dylib(версия совместимости 1.0.0, текущая версия 1.0.0)

/usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib(версия совместимости 1.0.0, текущая версия 1.0.0)

/usr/lib/libSystem.B.dylib(версия совместимости 1.0.0, текущая версия 1225.1.1)

Если вы выполняете brew info openssl, он замечает в CAVEATS:

Файл CA загрузился с использованием сертификатов из системы Брелок. Чтобы добавить дополнительные сертификаты, поместите файлы .pem в   /USR/ локальные/и т.д./OpenSSL/сертификаты

но явно по какой-то причине python не использует алгоритм opensl homebrew для поиска сертификатов.

Итак, я не понимаю, почему стандартная библиотека Python не проверяет сертификаты, которые находятся в каталоге OpenSSL, указанном в документах, так и в цепочке ключей (в форматах .pem и .p12), при этом "всегда доверять" "для Secure Sockets Layer (SSL)).

Ответ 1

Это ошибка dev_appserver, вызванная изменением поведения httplib.HTTPSConnection (проверка сертификата включена по умолчанию) в некоторой недавней версии Python (я верю 2.7.9).

Поскольку ошибка во внутреннем коде dev_appserver (файл google_appengine/google/appengine/api/urlfetch_stub.py SDK appengine), который запускается независимо от тестируемого приложения, нет способа сделать исправление, которое сохранится при обновлении SDK.

Единственное постоянное обходное решение, о котором я могу думать, это включить validate_certificate и добавить сертификат CA в файл urlfetch_cacerts.txt. В качестве временного исправления вы можете исправить urlfetch_stub.py с обходным путем № 3.

Ответ 2

Я столкнулся с той же проблемой в Windows. Я использовал старую версию Python (2.7). Когда я обновился до Python 2.7.11, проблема исчезла.