python ssl ssl.SSLError:[SSL:UNSUPPORTED_PROTOCOL]不支持的协议(_ssl.c:590)

时间:2015-09-01 11:52:44

标签: python ssl

使用python 2.7.10或2.7.9时出现此错误但与python 2.7.6一起使用(未测试其他版本)

OpenSLL版本:

openssl version -a
OpenSSL 1.0.1f 6 Jan 2014
built on: Thu Jun 11 15:30:15 UTC 2015
platform: debian-amd64
options:  bn(64,64) rc4(16x,int) des(idx,cisc,16,int) blowfish(idx)
compiler: cc -fPIC -DOPENSSL_PIC -DOPENSSL_THREADS -D_REENTRANT -DDSO_DLFCN -DHAVE_DLFCN_H -m64 -DL_ENDIAN -DTERMIO -g -O2 -fstack-protector-strong -Wformat -Werror=format-security -D_FORTIFY_SOURCE=2 -Wl,-Bsymbolic-functions -Wl,-z,relro -Wa,--noexecstack -Wall -DMD32_REG_T=int -DOPENSSL_IA32_SSE2 -DOPENSSL_BN_ASM_MONT -DOPENSSL_BN_ASM_MONT5 -DOPENSSL_BN_ASM_GF2m -DSHA1_ASM -DSHA256_ASM -DSHA512_ASM -DMD5_ASM -DAES_ASM -DVPAES_ASM -DBSAES_ASM -DWHIRLPOOL_ASM -DGHASH_ASM
OPENSSLDIR: "/usr/lib/ssl"

的Python:

import ssl
print ssl.OPENSSL_VERSION_NUMBER
268439663L
print get_server_certificate(('someInternalIp', 443), ssl_version=ssl.PROTOCOL_SSLv23)

堆栈跟踪:

File "C:\Python27\lib\ssl.py", line 985, in get_server_certificate
  with closing(context.wrap_socket(sock)) as sslsock:
File "C:\Python27\lib\ssl.py", line 352, in wrap_socket
  _context=self)
File "C:\Python27\lib\ssl.py", line 579, in __init__
  self.do_handshake()
File "C:\Python27\lib\ssl.py", line 808, in do_handshake
  self._sslobj.do_handshake()
ssl.SSLError: [SSL: UNSUPPORTED_PROTOCOL] unsupported protocol (_ssl.c:590)

3 个答案:

答案 0 :(得分:3)

显然python 2.7.6使用了这个密码套件:

DEFAULT:!aNULL:!eNULL:!LOW:!EXPORT:!SSLv2

现在它使用:

# Disable weak or insecure ciphers by default
# (OpenSSL's default setting is 'DEFAULT:!aNULL:!eNULL')
# Enable a better set of ciphers by default
# This list has been explicitly chosen to:
#   * Prefer cipher suites that offer perfect forward secrecy (DHE/ECDHE)
#   * Prefer ECDHE over DHE for better performance
#   * Prefer any AES-GCM over any AES-CBC for better performance and security
#   * Then Use HIGH cipher suites as a fallback
#   * Then Use 3DES as fallback which is secure but slow
#   * Disable NULL authentication, NULL encryption, and MD5 MACs for security
#     reasons
_DEFAULT_CIPHERS = (
    'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:'
    'DH+HIGH:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES:!aNULL:'
    '!eNULL:!MD5'
)

我必须构建以下代码,以便在使用旧密码套件时通知我。我可以这样做是因为我对检索证书感兴趣

from socket import socket
from ssl import SSLContext
from ssl import PROTOCOL_SSLv23
from ssl import DER_cert_to_PEM_cert

WEAK_CTX = SSLContext(PROTOCOL_SSLv23)
WEAK_CTX.set_ciphers('ALL:!aNULL:!eNULL')

NORMAL_CTX = SSLContext(PROTOCOL_SSLv23)
NORMAL_CTX.set_ciphers(
    'ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+HIGH:'
    'DH+HIGH:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+HIGH:RSA+3DES:!aNULL:'
    '!eNULL:!MD5'
)

def getCertificate(addr):
    sock = socket()
    sock.connect(addr)
    isWeakCipher = False
    try:
        sslobj = NORMAL_CTX._wrap_socket(sock._sock, server_side=False)
        sslobj.do_handshake()
    except Exception as ex:
        if hasattr(ex, 'reason') and ex.reason == 'SSLV3_ALERT_HANDSHAKE_FAILURE':
            sock.close()
            sock = socket()
            sock.connect(addr)
            sslobj = WEAK_CTX._wrap_socket(sock._sock, server_side=False)
            sslobj.do_handshake()
            isWeakCipher = True
        else:
            raise
    cipher = sslobj.cipher()

    cert = sslobj.peer_certificate(True)
    sock.close()
    return isWeakCipher, cipher, cert 

答案 1 :(得分:2)

如果您在基于debian的OS或docker映像中运行请求,则需要更改SSL配置。默认情况下,Debian目前可用于SSL v1.2 +。

您可以根据需要手动编辑openssl.cnf,但是有一个更快的解决方案:

sed -i 's/MinProtocol = TLSv1.2/MinProtocol = TLSv1.0/' /etc/ssl/openssl.cnf

对于我来说,这很有帮助,对使用旧SSL的URL的请求现在可以返回200响应。

答案 2 :(得分:0)

您的服务器可能正在暴露TLS协议的旧的,不安全的版本,而现代OpenSSL配置为不允许该协议。

https://stackoverflow.com/a/53065682/6214034可能会有帮助。