在Python中打开SSL套接字连接

55

我正在尝试在Python中建立一个安全的套接字连接,但SSL部分让我很苦恼。我找到了一些代码示例,介绍如何使用SSL建立连接,但它们都涉及到密钥文件。我要连接的服务器不需要接收任何密钥或证书。我的问题是,如何基本上用SSL包装Python套接字连接。我知道我应该使用的密码是ADH-AES256-SHA,协议是TLSv1。这就是我一直在尝试的:

import socket
import ssl

# SET VARIABLES
packet, reply = "<packet>SOME_DATA</packet>", ""
HOST, PORT = 'XX.XX.XX.XX', 4434

# CREATE SOCKET
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(10)

# WRAP SOCKET ???
ssl.wrap_socket(sock, ssl_version="TLSv1", ciphers="ADH-AES256-SHA")

# CONNECT AND PRINT REPLY
sock.connect((HOST, PORT))
sock.send(packet)
print sock.recv(1280)

# CLOSE SOCKET CONNECTION
sock.close()
当我运行这段代码时,没有出现任何错误,但是我得到了一个空白响应。 在尝试在命令行中调试此代码时,通过在终端中键入python并逐行粘贴代码,当运行sock.send(packet)时,获取的是一个整数响应码,我认为它是状态码。 我得到的整数响应是26。 如果有人知道这是什么意思,或者能以任何方式提供帮助,将不胜感激。
4个回答

98

好的,我弄清楚了问题所在。这有点儿愚蠢。我的代码有两个问题。第一个错误是在指定 ssl_version 时,我输入了 TLSv1 ,但应该是 ssl.PROTOCOL_TLSv1。 第二个错误是我没有引用包装后的套接字,而是调用了我创建的原始套接字。以下代码对我有效。

import socket
import ssl

# SET VARIABLES
packet, reply = "<packet>SOME_DATA</packet>", ""
HOST, PORT = 'XX.XX.XX.XX', 4434

# CREATE SOCKET
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(10)

# WRAP SOCKET
wrappedSocket = ssl.wrap_socket(sock, ssl_version=ssl.PROTOCOL_TLSv1, ciphers="ADH-AES256-SHA")

# CONNECT AND PRINT REPLY
wrappedSocket.connect((HOST, PORT))
wrappedSocket.send(packet)
print wrappedSocket.recv(1280)

# CLOSE SOCKET CONNECTION
wrappedSocket.close()

希望这能帮助到某些人!


4
我遇到了这个错误:ssl.SSLError: [SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] sslv3 alert handshake failure。有什么想法吗? - Kostanos
仅从输出很难判断。您使用了上面的代码片段吗?如果没有,我建议您打开一个新问题并发布您正在使用的代码 :) - Raffi
1
[SSL: WRONG_VERSION_NUMBER] 错误的版本号 (_ssl.c:590)。出现在 GNU/Linux (Ubuntu 16.04) 中。 - e-info128
@Kostanos 您可以尝试使用不同的加密方式。例如,将 ADH-AES256-SHA 替换为 AES256-SHA。如果这样仍然无法解决问题,请尝试使用 TLSv1.2AES256-SHA256。很可能是服务器不支持该加密方式或协议。 - Rahul Bharadwaj

11

您不应该设置PROTOCOL_TLSv1(或TLSv1)。这将仅限制连接到TLSv1.0。相反,您需要PROTOCOL_TLS(或已废弃的PROTOCOL_SSLv23),它支持库支持的所有版本。

您正在使用匿名密码,因为出于某种原因,您认为您不需要证书或密钥。这意味着没有对服务器进行身份验证,并且您容易遭受中间人攻击。除非您确切知道自己在做什么,否则建议您不要使用匿名密码(如ADH-AES256-SHA)。


16
可以举例说明如何实施证书或密钥,而不仅仅是说不要使用匿名密码? - user4805123
就目前而言,PROTOCOL_TLS也已被弃用,建议使用PROTOCOL_TLS_CLIENTPROTOCOL_TLS_SERVER。请参阅https://docs.python.org/3/library/ssl.html获取最新信息。 - undefined

10

我正在寻找一个好用的SSL套接字,该套接字使用https包开始连接。这篇文章帮了我很多,但有点过时了,所以在这里提供Python3的代码:

import socket
import ssl

package = "GET /ws/LiveWebcastUpdate/22000557 HTTP/1.1\r\nHost: 
www.website_name.com\r\nUser-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; 
rv:80.0) Gecko/20100101 Firefox/80.0\r\nAccept: */*\r\nAccept-Language: nl,en- 
US;q=0.7,en;q=0.3\r\nSec-WebSocket-Version: 13\r\nOrigin: 
https://www.website_name.com\r\nSec-WebSocket-Key: 
NU/EsJMICjSociJ751l0Xw==\r\nConnection: keep-alive, Upgrade\r\nPragma: no- 
cache\r\nCache-Control: no-cache\r\nUpgrade: websocket\r\n\r\n"

hostname = 'www.website_name.com'
port = 443

context = ssl.create_default_context()

with socket.create_connection((hostname, port)) as sock:
    with context.wrap_socket(sock, server_hostname=hostname) as ssock:
        print(ssock.version())
        ssock.send(package.encode())
        while True:
            data = ssock.recv(2048)
            if ( len(data) < 1 ) :
                break
            print(data)

这很简单,欲了解更多信息请访问https://docs.python.org/3/library/ssl.html

0

解决这些问题可以带来很多乐趣,但对我而言,我发现 Python SSL 的基础架构是 OpenSSL。在尝试让 Python 使用相同的栈之前,请使用 OpenSSL 验证您的证书。

在验证叶子证书之前,我需要将根证书导入到 OpenSSL 中。

这篇文章非常有帮助。
http://gagravarr.org/writing/openssl-certs/others.shtml#ca-openssl

另一个有趣的事情是,在不同主机上的相同版本的 Python 的两个不同构建具有不同的方法。一个具有 ssl.get_default_verify_paths(),而另一个则没有。其中的教训是 Python SSL 建立在 OpenSSL 上。不同的底层库会给你不同的 Python。

Python SSL 是建立在 OpenSSL 上的,因此请先解决 OpenSSL 中的证书问题。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接