Requests: فشل في حزم TLS الأقدم مع OpenSSL 1.1.1pre9

تم إنشاؤها على ٥ سبتمبر ٢٠١٨  ·  12تعليقات  ·  مصدر: psf/requests

قد يتسبب الاعتماد المرتقب لـ OpenSSL 1.1 (أو بشكل أكثر تحديدًا 1.1.1 ) بواسطة توزيعات Linux في حدوث مشكلات للطلبات عند التحقق من مواقع الويب القديمة.

تم الإبلاغ عن هذا لأول مرة في Debian bugtracker باعتباره الخطأ رقم 907807 ، وكان في الأصل ضد برنامج linkchecker (وتم إعادة توجيهه إلى الأعلى كـ https://github.com/linkchecker/linkchecker/issues/188) ، ولكن تبين أن مكتبة الطلبات تعاني بشكل مباشر من هذه المشكلة أيضًا.

~ من المحتمل أن تؤدي هذه المشكلة إلى حظر إصدار الطلبات باستخدام باستر ، والإصدار الحالي "التجريبي" والإصدار المستقر القادم (منتصف 2019؟) ما لم يتم إصلاحه إلى حد ما. ~ كان هذا التأكيد غير صحيح: تم وضع علامة على الخطأ حاليًا بـ "عادي" الشدة التي لا تمنع الافراج.

كانت المواقع المختبرة:

يتم تحميل جميع المواقع بشكل صحيح في Firefox 60.1.0 وعلى الرغم من أنني لم أختبر ذلك مع OpenSSL 1.1.1 ، أشك في أنه سيتأثر لأن Firefox (و Chromium) لهما مكتبة TLS الخاصة بهما (NSS). لاحظ أيضًا أن urllib3 يبدو أنه ليس لديه مشكلة في تحميل تلك المواقع نفسها:

>>> import urllib3
>>> http = urllib3.PoolManager()
>>> r = http.request('GET', 'https://get.adobe.com/')
>>> 

نتيجة متوقعة

يجب تحميل جميع المواقع بشكل صحيح ، والتحميل بشكل صحيح في Debian buster (والذي لا يزال يحتوي على OpenSSL 1.1.0):

$ python
Python 2.7.15+ (default, Aug 31 2018, 11:56:52) 
[GCC 8.2.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import requests
>>> requests.get('https://get.adobe.com')
<Response [200]>

نتيجة فعلية

(unstable-amd64-sbuild)anarcat<strong i="10">@curie</strong>:/$ python
Python 2.7.15+ (default, Aug 31 2018, 11:56:52) 
[GCC 8.2.0] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import requests
 >>> requests.get('https://get.adobe.com')
 Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
   File "/usr/lib/python2.7/dist-packages/requests/api.py", line 72, in get
     return request('get', url, params=params, **kwargs)
   File "/usr/lib/python2.7/dist-packages/requests/api.py", line 58, in request
     return session.request(method=method, url=url, **kwargs)
   File "/usr/lib/python2.7/dist-packages/requests/sessions.py", line 508, in request
     resp = self.send(prep, **send_kwargs)
   File "/usr/lib/python2.7/dist-packages/requests/sessions.py", line 618, in send
     r = adapter.send(request, **kwargs)
   File "/usr/lib/python2.7/dist-packages/requests/adapters.py", line 506, in send
     raise SSLError(e, request=request)
 requests.exceptions.SSLError: HTTPSConnectionPool(host='get.adobe.com', port=443): Max retries exceeded with url: / (Caused by SSLError(SSLError(1, u'[SSL: WRONG_SIGNATURE_TYPE] wrong signature type (_ssl.c:726)'),))
 >>> requests.get('https://www.nada.kth.se')
 Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
   File "/usr/lib/python2.7/dist-packages/requests/api.py", line 72, in get
     return request('get', url, params=params, **kwargs)
   File "/usr/lib/python2.7/dist-packages/requests/api.py", line 58, in request
     return session.request(method=method, url=url, **kwargs)
   File "/usr/lib/python2.7/dist-packages/requests/sessions.py", line 508, in request
     resp = self.send(prep, **send_kwargs)
   File "/usr/lib/python2.7/dist-packages/requests/sessions.py", line 618, in send
     r = adapter.send(request, **kwargs)
   File "/usr/lib/python2.7/dist-packages/requests/adapters.py", line 506, in send
     raise SSLError(e, request=request)
 requests.exceptions.SSLError: HTTPSConnectionPool(host='www.nada.kth.se', port=443): Max retries exceeded with url: / (Caused by SSLError(SSLError(1, u'[SSL: DH_KEY_TOO_SMALL] dh key too small (_ssl.c:726)'),))
 >>> requests.get('https://caniuse.com')
 Traceback (most recent call last):
   File "<stdin>", line 1, in <module>
   File "/usr/lib/python2.7/dist-packages/requests/api.py", line 72, in get
     return request('get', url, params=params, **kwargs)
   File "/usr/lib/python2.7/dist-packages/requests/api.py", line 58, in request
     return session.request(method=method, url=url, **kwargs)
   File "/usr/lib/python2.7/dist-packages/requests/sessions.py", line 508, in request
     resp = self.send(prep, **send_kwargs)
   File "/usr/lib/python2.7/dist-packages/requests/sessions.py", line 618, in send
     r = adapter.send(request, **kwargs)
   File "/usr/lib/python2.7/dist-packages/requests/adapters.py", line 506, in send
     raise SSLError(e, request=request)
 requests.exceptions.SSLError: HTTPSConnectionPool(host='caniuse.com', port=443): Max retries exceeded with url: / (Caused by SSLError(SSLError(1, u'[SSL: VERSION_TOO_LOW] version too low (_ssl.c:726)'),))

خطوات التكاثر

قم بتشغيل آلة غير مستقرة في دبيان للحصول على أحدث حزمة 1.1.1 ~~ pre9. يمكن القيام بذلك باستخدام Docker باستخدام:

docker run -it debian:unstable

إذا لم يكن لديك وصول إلى مثل هذه البيئة ، فيمكن العثور على أحدث كود OpenSSL في صفحة المشروع الخاصة بهم .

import requests

for url in ('https://get.adobe.com/', 'https://caniuse.com',
'https://www.nada.kth.se/~snilsson/publications/IP-address-lookup-using-LC-tries/'):
    requests.get(url)

معلومات النظام

$ python -m requests.help
(unstable-amd64-sbuild)anarcat<strong i="16">@curie</strong>:/$ python -m requests.help
{
  "chardet": {
    "version": "3.0.4"
  }, 
  "cryptography": {
    "version": ""
  }, 
  "idna": {
    "version": "2.6"
  }, 
  "implementation": {
    "name": "CPython", 
    "version": "2.7.15+"
  }, 
  "platform": {
    "release": "4.17.0-3-amd64", 
    "system": "Linux"
  }, 
  "pyOpenSSL": {
    "openssl_version": "", 
    "version": null
  }, 
  "requests": {
    "version": "2.18.4"
  }, 
  "system_ssl": {
    "version": "10101009"
  }, 
  "urllib3": {
    "version": "1.22"
  }, 
  "using_pyopenssl": false
}

إنني على دراية بأننا أحد الإصدارات الثانوية وراء المنبع في دبيان ، ويتم العمل على هذا الأمر. لكنني راجعت طلبات التغيير ولا يبدو أن هناك أي تغيير ذي صلة بهذا. لذلك فأنا أؤكد أن الإصدارات الحالية تعاني أيضًا من نفس المشكلة.

لاحظ أيضًا أن هذا قد يكون انحدارًا في OpenSSL نفسه. أقوم بحفظ هذا هنا لمعرفة رأيك فيما يتعلق بهذه المشكلة وما إذا كان شيئًا ينتمي إلى الطلبات أو مكتبة (مكتبات) التشفير الأولية.

التعليق الأكثر فائدة

يعمل ما يلي بالنسبة لي:

import requests
from requests import adapters
import ssl
from urllib3 import poolmanager


class TLSAdapter(adapters.HTTPAdapter):

    def init_poolmanager(self, connections, maxsize, block=False):
        """Create and initialize the urllib3 PoolManager."""
        ctx = ssl.create_default_context()
        ctx.set_ciphers('DEFAULT@SECLEVEL=1')
        self.poolmanager = poolmanager.PoolManager(
                num_pools=connections,
                maxsize=maxsize,
                block=block,
                ssl_version=ssl.PROTOCOL_TLS,
                ssl_context=ctx)

session = requests.session()
session.mount('https://', TLSAdapter())
session.get(TARGET)

ال 12 كومينتر

بالنسبة لمشكلة Adobe التي فتحتها: https://github.com/openssl/openssl/issues/7126

مشكلة caniuse هي: https://github.com/Fyrd/caniuse/issues/4198

يرجع السبب في ذلك إلى قيام Debian بإعداد إصدار TLS بحد أدنى 1.2. يجب عليهم بالفعل إضافة دعم TLS 1.2 على الأقل.

لمشكلة SNI ، راجع: https://wiki.openssl.org/index.php/TLS1.3#Server_Name_Indication

ستواجه هذه المشكلة لأي شيء تستضيفه Google.

لذا فإن بعض هذه المشكلات ناتجة عن زيادة دبيان لمستوى أمان openssl افتراضيًا. الإصلاح المناسب هو إصلاح مواقع الويب. لكن من الممكن خفض إعدادات الأمان هذه كحل بديل. من فضلك لا تتجاوز الإعدادات الافتراضية بشكل افتراضي.

مشكلة SNI شيء يجب عليك إصلاحه حقًا. لا أعرف أي جزء لا يضبطه.

مرحبا ، هل يمكنك تقديم الحلول؟ لقد حاولت خفض اتصال الأمان لتجنب DH_KEY_TOO_SMALL ، لكن لم أجد أي حل يناسبني (اختبار Debian ، الطلبات المثبتة من حزمة debian). على وجه التحديد لـ https://www.ceskatelevize.cz/ . ليس من المحتمل جدًا أن يقوموا بإصلاح الأمان في أي وقت قريبًا.

انظر /usr/share/doc/libssl1.1/NEWS.Debian.gz

لقد رأيت ذلك ، لكنني لا أرغب في خفض مستوى الأمان للنظام بأكمله ، فقط لبرنامج نصي محدد. لقد جربت أيضًا https://stackoverflow.com/q/38015537/2440346 ، لكن تغيير urllib3.util.ssl_.DEFAULT_CIPHERS لا يعمل أيضًا.

إذا كنت تريد خفض إعداد الأمان في ملف آخر بخلاف
/etc/ssl/openssl.cfg تحتاج إلى استخدام DEFAULT @ SECLEVEL = 1

لقد جربت عددًا من الأساليب ، لكن لم ينجح أي منها ، انظر

import requests
from requests.adapters import HTTPAdapter
from requests.packages.urllib3.util.ssl_ import create_urllib3_context

# Attempt 1:
# requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS = '@SECLEVEL=1'
# Attempt 2:
# requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS = 'DEFAULT@SECLEVEL=1'
# Attempt 3:
# requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS = 'ALL'
requests.get('https://www.ceskatelevize.cz/')

# Attempt 4:
# CIPHERS = '@SECLEVEL=1'
# Attempt 5:
# CIPHERS = 'DEFAULT@SECLEVEL=1'
# Attempt 6:
CIPHERS = 'ALL'
class CustomAdapter(HTTPAdapter):
    """
    A TransportAdapter that re-enables 3DES support in Requests.
    """
    def init_poolmanager(self, *args, **kwargs):
        context = create_urllib3_context(ciphers=CIPHERS)
        kwargs['ssl_context'] = context
        return super(CustomAdapter, self).init_poolmanager(*args, **kwargs)

    def proxy_manager_for(self, *args, **kwargs):
        context = create_urllib3_context(ciphers=CIPHERS)
        kwargs['ssl_context'] = context
        return super(CustomAdapter, self).proxy_manager_for(*args, **kwargs)

session = requests.Session()
session.mount('https://www.ceskatelevize.cz', CustomAdapter())
session.get('https://www.ceskatelevize.cz/')

يعمل ما يلي بالنسبة لي:

import requests
from requests import adapters
import ssl
from urllib3 import poolmanager


class TLSAdapter(adapters.HTTPAdapter):

    def init_poolmanager(self, connections, maxsize, block=False):
        """Create and initialize the urllib3 PoolManager."""
        ctx = ssl.create_default_context()
        ctx.set_ciphers('DEFAULT@SECLEVEL=1')
        self.poolmanager = poolmanager.PoolManager(
                num_pools=connections,
                maxsize=maxsize,
                block=block,
                ssl_version=ssl.PROTOCOL_TLS,
                ssl_context=ctx)

session = requests.session()
session.mount('https://', TLSAdapter())
session.get(TARGET)

يعمل ما يلي بالنسبة لي:

import requests
from requests import adapters
import ssl
from urllib3 import poolmanager


class TLSAdapter(adapters.HTTPAdapter):

    def init_poolmanager(self, connections, maxsize, block=False):
        """Create and initialize the urllib3 PoolManager."""
        ctx = ssl.create_default_context()
        ctx.set_ciphers('DEFAULT@SECLEVEL=1')
        self.poolmanager = poolmanager.PoolManager(
                num_pools=connections,
                maxsize=maxsize,
                block=block,
                ssl_version=ssl.PROTOCOL_TLS,
                ssl_context=ctx)

session = requests.session()
session.mount('https://', TLSAdapter())
session.get(TARGET)

شكرا!
إنه مفيد لخطأ SSLE الخاص بي [SSL: DH_KEY_TOO_SMALL]

@ codefather-labs شكرًا كان لدي نفس المشكلة ، غريب جدًا

هل كانت هذه الصفحة مفيدة؟
0 / 5 - 0 التقييمات