【问题标题】:SSL error unsafe legacy renegotiation disabledSSL 错误不安全旧版重新协商已禁用
【发布时间】:2022-11-09 00:51:14
【问题描述】:

我正在运行一个 Python 代码,我必须从 HTTPSConnectionPool(host='ssd.jpl.nasa.gov', port=443) 获取一些数据。但是每次我尝试运行代码时,都会出现以下错误。我在 MAC OS 12.1

raise SSLError(e, request=request)
requests.exceptions.SSLError: HTTPSConnectionPool(host='ssd.jpl.nasa.gov', port=443): Max retries exceeded with url: /api/horizons.api?format=text&EPHEM_TYPE=OBSERVER&QUANTITIES_[...]_ (Caused by SSLError(SSLError(1, '[SSL: UNSAFE_LEGACY_RENEGOTIATION_DISABLED] unsafe legacy renegotiation disabled (_ssl.c:997)')))

我真的不知道如何绕过这个问题..谢谢你的帮助!

【问题讨论】:

    标签: python ssl openssl runtime-error


    【解决方案1】:

    警告:启用旧版不安全重新协商时,SSL 连接将容易受到 CVE-2009-3555 中所述的中间人前缀攻击。

    https://bugs.launchpad.net/bugs/1963834的帮助下 和https://bugs.launchpad.net/ubuntu/+source/gnutls28/+bug/1856428

    请注意,不建议编辑系统的 openssl.conf,因为一旦更新 openssl,您可能会丢失更改。

    在任何目录中使用以下内容创建自定义 openssl.cnf 文件:

    openssl_conf = openssl_init
    
    [openssl_init]
    ssl_conf = ssl_sect
    
    [ssl_sect]
    system_default = system_default_sect
    
    [system_default_sect]
    Options = UnsafeLegacyRenegotiation
    

    在运行你的程序之前,确保你的 OPENSSL_CONF 环境变量设置为你自定义的 openssl.cnf 在运行刮板时的完整路径,如下所示:

    OPENSSL_CONF=/path/to/custom/openssl.cnf python your_scraper.py
    

    或者像这样:

    export OPENSSL_CONF=/path/to/custom/openssl.cnf
    python your_scraper.py
    

    或者,如果您使用的是 pipenv 或 systemd 或 docker,请将其放入您的 .env 文件中

    OPENSSL_CONF=/path/to/custom/openssl.cnf
    

    【讨论】:

    • 这也对我有用,尽管我并不完全不明白我在做什么。 (只是想获得 TD ameritrade 股票。在升级到 22.04 之前一直在工作)要编辑的文件是 Modify the existing openssl config file, path: /usr/lib/ssl/openssl.cnf
    • @Chad 不建议更改系统默认值,因为它们可能会被包更改覆盖。发生在每个人身上。有一种更简洁的方法,我正在编辑答案以发布一个工作示例。
    【解决方案2】:

    使用 OpenSSL 3 连接到不支持它的服务器时会出现此错误。解决方案是在python中降级密码学包:

    在使用的环境中运行pip install cryptography==36.0.2

    来源:https://github.com/scrapy/scrapy/issues/5491

    编辑:请参阅 Hally Mallon 和 ahmkara 的答案以获得修复,而无需降级密码学

    【讨论】:

    • 不适合我和api.searchads.apple.com
    • 我通过密码学 37.0.2 对 python 请求 2.28.1 有同样的问题。我将密码学降级为 36.0.2 并修复了问题。 tnx 很多 :X
    【解决方案3】:

    我在 Linux 上遇到了同样的错误(当服务器不支持“RFC 5746 安全重新协商”并且客户端使用 OpenSSL 3,默认情况下强制执行该标准时)。

    这是一个解决方案(您可能需要稍微调整一下)。

    1. 在 Python 代码中导入 sslurllib3
    2. 创建一个使用自定义sslContext的自定义HttpAdapter
      class CustomHttpAdapter (requests.adapters.HTTPAdapter):
          '''Transport adapter" that allows us to use custom ssl_context.'''
      
          def __init__(self, ssl_context=None, **kwargs):
              self.ssl_context = ssl_context
              super().__init__(**kwargs)
      
          def init_poolmanager(self, connections, maxsize, block=False):
              self.poolmanager = urllib3.poolmanager.PoolManager(
                  num_pools=connections, maxsize=maxsize,
                  block=block, ssl_context=self.ssl_context)
      
      1. 设置启用OP_LEGACY_SERVER_CONNECTssl 上下文,并将其与您的自定义适配器一起使用。

      ssl.OP_LEGACY_SERVER_CONNECT 在 Python 中尚不可用 (https://bugs.python.org/issue44888)。然而事实证明,在 OpenSSL 中,它的值在位域中是 0x4。所以我们可以做到以下几点。

      ctx = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
      ctx.options |= 0x4
      session.mount('https://', CustomHttpAdapter(ctx))
      

    【讨论】:

    • 嘿哈利!我尝试使用您的代码,但我得到未解决的请求参考。和会议。因为它们没有定义
    • sessionrequests.Session() 的一个实例。我的代码 sn-ps 不完整,因为它们取自一个更大的项目。您将不得不调整它们以适合您的代码。
    • 这会导致:ValueError:启用 check_hostname 时无法将 verify_mode 设置为 CERT_NONE。只需添加,然后它应该运行 >>> ctx.check_hostname = False >>> ctx.verify_mode = ssl.CERT_NONE
    • 这也对我有用,可能是降级的最佳未来证明替代方案
    • 可以确认此解决方案有效!无需根据接受的答案降级。
    【解决方案4】:

    Harry Mallon答案的完整代码sn-ps:

    定义重用方法:

    import requests
    import urllib3
    import SSL
    
    
    class CustomHttpAdapter (requests.adapters.HTTPAdapter):
        # "Transport adapter" that allows us to use custom ssl_context.
    
        def __init__(self, ssl_context=None, **kwargs):
            self.ssl_context = ssl_context
            super().__init__(**kwargs)
    
        def init_poolmanager(self, connections, maxsize, block=False):
            self.poolmanager = urllib3.poolmanager.PoolManager(
                num_pools=connections, maxsize=maxsize,
                block=block, ssl_context=self.ssl_context)
    
    
    def get_legacy_session():
        ctx = ssl.create_default_context(ssl.Purpose.SERVER_AUTH)
        ctx.options |= 0x4  # OP_LEGACY_SERVER_CONNECT
        session = requests.session()
        session.mount('https://', CustomHttpAdapter(ctx))
        return session
    

    然后使用它代替 requests 调用:

    get_legacy_session().get("some-url")
    

    【讨论】:

    • 好的!我现在只是使用了with (get_legacy_session() as s, s.get("some-url") as response),它可以工作。对于在谷歌云中部署非常有用(因为我无法在此处降级 SSL)
    • 不工作 ''' r = get_legacy_session().post(url, params=params, data=payload) '''
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-01
    • 2018-07-25
    • 1970-01-01
    • 2011-09-16
    • 2014-07-30
    • 2021-05-03
    相关资源
    最近更新 更多