杰瑞科技汇

Python 2.7 如何升级 OpenSSL?

Of course. This is a very common topic, especially for maintaining legacy systems. Here's a comprehensive guide to using Python 2.7 with OpenSSL, covering the built-in library, common issues, and modern alternatives.

Python 2.7 如何升级 OpenSSL?-图1
(图片来源网络,侵删)

The Built-in ssl Module

Python 2.7 includes a built-in ssl module. This module is a Python wrapper around the OpenSSL library that your Python interpreter was compiled against.

Key Characteristics of Python 2.7's ssl Module:

  • Outdated by Default: The version of OpenSSL that Python 2.7 is linked to is often very old (e.g., OpenSSL 1.0.1 or 1.0.2). These versions have known security vulnerabilities (like Heartbleed) and lack support for modern protocols and ciphers.
  • Limited Protocol Support: It defaults to the insecure SSLv23 method, which is actually a negotiation protocol. This can lead to it falling back to very old, insecure protocols like SSLv3 or TLSv1 if the server supports them.
  • No SNI (Server Name Indication) Support: This is a major limitation. SNI allows a single server to host multiple SSL certificates on one IP address. Without it, you might have trouble connecting to modern sites that require it.
  • No ALPN (Application-Layer Protocol Negotiation): This is required for HTTP/2, so you can't use modern Python 2.7 HTTP libraries to connect to HTTP/2 servers.

Common Problem: ssl.SSLError: [SSL: SSLV3_ALERT_HANDSHAKE_FAILURE]

This is the most frequent error you'll encounter. It usually means the remote server has disabled support for the old, insecure protocols that Python 2.7's default ssl module tries to use.

Solution 1: Force a Modern Protocol (The Quick Fix)

You can explicitly tell the ssl module to use a more modern protocol like TLSv1. This is better than the default but still not ideal, as it lacks modern ciphers and security features.

import ssl
import urllib2
# Create a more secure SSL context
# PROTOCOL_TLSv1_1 or PROTOCOL_TLSv1 are available in Python 2.7.9+
# For older Python 2.7 versions, PROTOCOL_SSLv23 is the only option,
# but we can set options to disable old protocols.
context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
context.options |= ssl.OP_NO_SSLv2
context.options |= ssl.OP_NO_SSLv3
context.options |= ssl.OP_NO_TLSv1 # Optional: if you want to force TLS 1.2+
# For Python 2.7.9+, you can be more specific:
# context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
try:
    # Install the context into the default opener
    opener = urllib2.build_opener(urllib2.HTTPSHandler(context=context))
    urllib2.install_opener(opener)
    response = urllib2.urlopen('https://www.howsmyssl.com', timeout=10)
    print response.read()
except ssl.SSLError as e:
    print "SSL Error:", e
except Exception as e:
    print "General Error:", e

Solution 2: Use a Backport Library (The Recommended Fix)

The best way to modernize Python 2.7's SSL capabilities is to use a backport library like pyOpenSSL. This library links against a modern, system-wide OpenSSL installation (e.g., OpenSSL 1.1.x) instead of the old one Python was compiled with.

Python 2.7 如何升级 OpenSSL?-图2
(图片来源网络,侵删)

Install a modern OpenSSL on your system:

  • On Debian/Ubuntu:

    sudo apt-get update
    sudo apt-get install libssl-dev

    This will likely install OpenSSL 1.1.x.

  • On RHEL/CentOS:

    Python 2.7 如何升级 OpenSSL?-图3
    (图片来源网络,侵删)
    sudo yum install openssl-devel

    This will likely install OpenSSL 1.0.x. For a newer version, you may need to use EPEL or compile from source.

Install pyOpenSSL:

pip install pyOpenSSL

Use pyOpenSSL in your code:

pyOpenSSL provides a different API. It's often used with requests, which can be configured to use pyOpenSSL as its SSL backend.

import requests
from requests.packages.urllib3.contrib.pyopenssl import inject_into_urllib3
from requests.packages.urllib3.util.ssl_ import create_urllib3_context
# Inject pyOpenSSL's SSLContext into urllib3
# This makes 'requests' use the modern OpenSSL from pyOpenSSL
inject_into_urllib3()
# Now, when you make a request, it will use the modern backend
try:
    # The context will be created by the injected pyOpenSSL
    response = requests.get('https://www.howsmyssl.com', timeout=10)
    print response.text
except Exception as e:
    print "Error:", e

This approach is the most robust for getting modern SSL/TLS behavior in Python 2.7.


A Complete Example: Making a Secure Request

Here is a complete, recommended example that uses the requests library with the pyOpenSSL backport. This is the most practical and secure way to handle HTTPS in Python 2.7 today.

Step 1: Ensure you have the prerequisites

# Install a modern system OpenSSL
sudo apt-get install libssl-dev
# Install Python libraries
pip install requests
pip install pyOpenSSL

Step 2: The Python Code

# modern_ssl_request.py
import requests
import sys
# This import is key. It monkey-patches urllib3 to use pyOpenSSL.
# This makes 'requests' use the modern OpenSSL library instead of the old one.
from requests.packages.urllib3.contrib.pyopenssl import inject_into_urllib3
def make_secure_request(url):
    """
    Makes an HTTPS request using modern SSL/TLS via pyOpenSSL.
    """
    print "Making a secure request to:", url
    print "Python version:", sys.version
    print "Using pyOpenSSL for modern SSL support."
    # Inject the pyOpenSSL SSLContext
    inject_into_urllib3()
    try:
        # The 'verify=True' is important for certificate validation
        response = requests.get(url, timeout=15, verify=True)
        # Check if the request was successful
        response.raise_for_status()
        print "\n--- Success! ---"
        print "Status Code:", response.status_code
        print "Server Protocol:", response.raw.version
        print "Cipher:", response.raw._connection.sock.cipher() # Access underlying socket info
        # Example: Check the connection info from howsmyssl.com
        if 'howsmyssl.com' in url:
            print "SSL/TLS Grade:", response.text.split('<th>SSL/TLS Grade</th>')[1].split('</td>')[0].strip()
    except requests.exceptions.SSLError as e:
        print "\n--- SSL Error ---"
        print "This likely means the server does not support old protocols or has an invalid certificate."
        print "Error details:", e
    except requests.exceptions.RequestException as e:
        print "\n--- Request Failed ---"
        print "Error details:", e
if __name__ == "__main__":
    # Test against a site that checks your SSL capabilities
    test_url = 'https://www.howsmyssl.com'
    make_secure_request(test_url)
    # Test against a site that has disabled old protocols
    # modern_github = 'https://api.github.com'
    # make_secure_request(modern_github)

When you run this script, you'll see that it successfully connects to modern servers and reports a good TLS grade, because it's using the power of pyOpenSSL and a modern system OpenSSL library.


Security Warning: The End of Python 2.7

This is the most important point.

Python 2.7 reached its official end-of-life on January 1, 2025. This means:

  • No Security Updates: No new security patches will be released for Python 2.7 itself or its standard library (including the ssl module).
  • Vulnerabilities: Any code running on Python 2.7 is vulnerable to all discovered security issues that have not been patched.
  • No Modern Features: You cannot use modern language features, and the ecosystem is frozen.

Recommendation: The only long-term solution is to migrate your application to Python 3. Python 3.6 and newer have excellent, up-to-date ssl support by default, are secure, and receive active support. While using pyOpenSSL can patch the SSL issues, it does not fix the fundamental security and maintenance problems of running on Python 2.7.

分享:
扫描分享到社交APP
上一篇
下一篇