使用 HTTPS 代理的套接字上的 HTTPS 数据
Posted
技术标签:
【中文标题】使用 HTTPS 代理的套接字上的 HTTPS 数据【英文标题】:HTTPS data over socket using HTTPS proxy 【发布时间】: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>
无论我做什么,我似乎都无法让服务器正确响应,我是否缺少标头?我正在阅读其他一些 *** 帖子,有些人提到我需要双重包装套接字,但是我不太确定从哪里开始。
任何信息都会令人愉快。
感谢您的帮助,
谢谢。
# 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
,你需要翻转它。
【参考方案1】:
不知道这是否正确,但经过一番折腾,我设法想出了这个,并且它有效。
import socket, ssl
sslSocket = ssl.wrap_socket(socket.socket(socket.AF_INET, socket.SOCK_STREAM))
# CONNECT TO PROXY
sslSocket.connect(('REMOTE_PROXY', 443))
# SEND GET REQUEST
sslSocket.send(b'GET https://api.ipify.org/ HTTP/1.1\r\nHost: api.ipify.org\r\nProxy-Authorization: Basic BASE64_USERPASS\r\n\r\n')
headers, body = sslSocket.recv(4096).decode(), sslSocket.recv(4096).decode()
print(headers, body)
【讨论】:
以上是关于使用 HTTPS 代理的套接字上的 HTTPS 数据的主要内容,如果未能解决你的问题,请参考以下文章
通过套接字连接将 https 代理请求传递到命名管道(node.js)
运行在 HTTPS/Web 套接字上的 Webpack 开发服务器安全
带有反向代理后面的HTTPS的build_absolute_uri