【发布时间】:2022-01-20 18:14:45
【问题描述】:
我希望通过通过套接字连接的 HTTPS 代理发送 HTTPS 数据。
我可以通过代理通过端口 80(在 CONNECT 中)发送数据,但是当我通过端口 443(在 CONNECT 中)发送数据时,我通常会收到 http 错误。举个例子:
HTTP/1.1 200 Connection established
HTTP/1.1 400 Bad Request
Server: awselb/2.0
Date: Fri, 17 Dec 2021 22:39:32 GMT
Content-Type: text/html
Content-Length: 220
Connection: close
<html>
<head><title>400 The plain HTTP request was sent to HTTPS port</title></head>
<body>
<center><h1>400 Bad Request</h1></center>
<center>The plain HTTP request was sent to HTTPS port</center>
</body>
</html>
我通过在标题中添加 Host: https://httpbin.org 而不是 Host: www.httpbin.org 来解决此问题,但是现在我收到了:
HTTP/1.1 200 Connection established
HTTP/1.1 400 Bad Request
Server: awselb/2.0
Date: Fri, 17 Dec 2021 22:49:30 GMT
Content-Type: text/html
Content-Length: 122
Connection: close
<html>
<head><title>400 Bad Request</title></head>
<body>
<center><h1>400 Bad Request</h1></center>
</body>
</html>
无论我做什么,我似乎都无法让服务器正确响应,我是否缺少标头?我正在阅读其他一些 stackoverflow 帖子,有些人提到我需要双重包装套接字,但是我不太确定从哪里开始。
任何信息都会令人愉快。
感谢您的帮助,
谢谢。
# first way i tried
#from OpenSSL import SSL
#sslSocket = SSL.Connection(SSL.Context(SSL.SSLv23_METHOD), socket.socket(socket.AF_INET, socket.SOCK_STREAM))
# second way i tried
import socket, ssl
sslSocket = ssl.wrap_socket(socket.socket(socket.AF_INET, socket.SOCK_STREAM))
# both of the above solutions work and end with the same result.
# CONNECT TO PROXY
sslSocket.connect(('remote_datacenter_proxy', 443))
# SEND CONNECT REQUEST
sslSocket.send(b'CONNECT httpbin.org:443 HTTP/1.1\r\nProxy-Authorization: Basic BASE_64_USERPASS\r\n\r\n')
response = sslSocket.recv(1024).decode('utf-8')
print(response)
# SEND GET REQUEST
sslSocket.send(b'GET /get HTTP/1.1\r\nHost: https://httpbin.org\r\nConnection: close\r\n\r\n')
response = sslSocket.recv(4096).decode('utf-8')
print(response)
【问题讨论】:
-
你必须先用
do_handshake_on_connect=false将socket连接到代理,然后将CONNECT的代理告诉HTTPS服务器,然后与HTTPS服务器发起TLS握手 使用sslSocket.do_handshake(),最后发送HTTP请求。您正在跳过 TLS 步骤,因此请求未加密。您必须与 HTTPS 服务器握手,而不是与代理握手。 -
您还需要从代理服务器和 HTTPS 服务器读取并正确解析各个 HTTP 响应。每个人都有一个
recv(1024)不会削减它。您需要正确遵循 HTTP 协议。这意味着读取响应行、响应标头、解析行和标头以确定消息正文的存在和格式,然后将正文读取到其自然结束。如果你不这样做,你会破坏你的通信。 -
@RemyLebeau 感谢您的快速回复,我将不得不更深入地了解一切是如何运作的。我可能会使用更高级别的库,例如 pycurl。我现在正在阅读ietf.org/rfc/rfc2817.txt。我试图做
sslSocket.do_handshake(),但它返回None,但是我想我正在与代理握手,现在是实际的HTTPS服务器。我认为它会像使用 HTTP 一样更直接 :) -
ssl.wrap_socket()默认有do_handshake_on_connect=true,你需要翻转它。
标签: python python-3.x sockets ssl