我正在编写一个程序来下载给定的网页。由于一些限制,我只需要使用原始python套接字进行所有连接。所以我建立了一个到给定域的套接字连接(对象的响应头中的主机字段),然后发送GET请求。现在,当url是https url时,我想我需要先进行SSL握手(因为否则我从服务器获得非200 OK响应以及其他提及P3P策略的错误响应)。我检查了curl的响应以检查它是如何能够成功下载而我不是,结果curl首先进行SSL握手(这就完全不同了)。 curl总是能够成功下载一个给定的对象,唯一的区别总是它所做的SSL握手。
所以我想知道如何在原始python套接字中进行SSL握手?基本上我想要一个简单的解决方案,除了使用原始套接字外,我还可以做到最小。
答案 0 :(得分:2)
以下是使用SLL的TCP客户端的示例。
不确定这是下载网页的最佳方式,但它应该回答您的问题“原始python套接字中的SSL握手”。
您可能需要调整struct.pack / unpack,但是您可以得到一般的想法:
import socket
import ssl
import struct
import binascii
import sys
class NotConnectedException(Exception):
def __init__(self, message=None, node=None):
self.message = message
self.node = node
class DisconnectedException(Exception):
def __init__(self, message=None, node=None):
self.message = message
self.node = node
class Connector:
def __init__(self):
pass
def is_connected(self):
return (self.sock and self.ssl_sock)
def open(self, hostname, port, cacert):
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.ssl_sock = ssl.wrap_socket(self.sock, ca_certs=cacert, cert_reqs=ssl.CERT_REQUIRED)
if hostname == socket.gethostname():
ipaddress = socket.gethostbyname_ex(hostname)[2][0]
self.ssl_sock.connect((ipaddress, port))
else:
self.ssl_sock.connect((hostname, port))
self.sock.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1)
def close(self):
if self.sock: self.sock.close()
self.sock = None
self.ssl_sock = None
def send(self, buffer):
if not self.ssl_sock: raise NotConnectedException("Not connected (SSL Socket is null)")
self.ssl_sock.sendall(struct.pack('L', len(buffer)))
self.ssl_sock.sendall(buffer)
def receive(self):
if not self.ssl_sock: raise NotConnectedException("Not connected (SSL Socket is null)")
data_size_buffer = self.ssl_sock.recv(4)
if len(data_size_buffer) <= 0:
raise DisconnectedException()
data_size = struct.unpack('L', data_size_buffer)[0]
received_size = 0
data_buffer = ""
while received_size < data_size:
chunk = self.ssl_sock.recv(1024)
data_buffer += chunk
received_size += len(chunk)
return data_buffer
然后你使用这样的类:
connector = Connector.Connector()
connector.open(server_ip, server_port, path_to_the_CA_cert.pem)
connector.send(your_data)
response = connector.receive()
connector.close()
答案 1 :(得分:0)
您可以使用python ssl模块的wrap_socket方法将您的套接字转换为使用SSL的套接字。完成此操作后,您可以像平常一样使用它,但在内部数据将为您加密和解密。这些是该方法的文档: https://docs.python.org/2/library/ssl.html#ssl.wrap_socket
答案 2 :(得分:0)