1

我面临以下情况:我被迫使用 HTTP 代理连接到 HTTPS 服务器。出于多种原因,我需要访问原始数据(在加密之前),因此我使用的是套接字库而不是 HTTP 特定库之一。因此,我首先将 TCP 套接字连接到 HTTP 代理并发出连接命令。

此时,HTTP 代理接受连接并似乎将所有进一步的数据转发到目标服务器。但是,如果我现在尝试切换到 SSL,我会收到

错误:140770FC:SSL 例程:SSL23_GET_SERVER_HELLO:未知协议

指示套接字尝试与 HTTP 代理而不是与 HTTPS 目标握手。

这是我到目前为止的代码:

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  
s.connect(('proxy',9502))  
s.send("""CONNECT en.wikipedia.org:443 HTTP/1.1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:15.0) Gecko/20100101 Firefox/15.0.1  
Proxy-Connection: keep-alive  
Host: en.wikipedia.org 

""")  

print s.recv(1000)  

ssl = socket.ssl(s, None, None)  
ssl.connect(("en.wikipedia.org",443))  

连接到 HTTP 代理后,打开到目标服务器的 SSL 套接字的正确方法是什么?

4

2 回答 2

1

(请注意,一般来说,使用现有的 HTTPS 库(例如 PyCurl)会更容易,而不是自己实现它。)

首先,不要调用你的变量ssl。该名称已被ssl模块使用,因此您不想隐藏它。

其次,不要使用connect第二次。你已经连接了,你需要的是包装套接字。由于 Python 默认不进行任何证书验证,因此您还需要验证远程证书并验证主机名。

以下是涉及的步骤:

  • 建立您的纯文本连接并CONNECT像前几行一样使用。
  • 阅读您收到的 HTTP 响应,并确保您收到 200 状态代码。(您需要逐行阅读标题)。
  • 用于ssl_s = ssl.wrap_socket(s, cert_reqs=ssl.CERT_REQUIRED, ssl_version=ssl.PROTOCOL_TLS1, ca_certs='/path/to/cabundle.pem')包裹插座。然后,验证主机名。值得一读这个答案connect包装套接字后的方法及其作用。
  • 然后,像使用ssl_s普通套接字一样使用它。不要再打电话connect了。
于 2013-03-17T16:46:40.597 回答
0

适用于 python 3
<proxy> 是 ip 或域名
<port> 443 或 80 或任何您的代理正在监听
<endpoint> 您要通过代理连接的最终服务器
<cn> 是一个可选的 sni 字段您的最终服务器可能期待

import socket,ssl

def getcert_sni_proxy(cn,endpoint,PROXY_ADDR=("<proxy>", <port>)):
    #prepare the connect phrase
    CONNECT = "CONNECT %s:%s HTTP/1.0\r\nConnection: close\r\n\r\n" % (endpoint, 443)

    #connect to the actual proxy
    conn = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    conn.connect(PROXY_ADDR)
    conn.send(str.encode(CONNECT))
    conn.recv(4096)
    
    #set the cipher for the ssl layer
    context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)

    #connect to the final endpoint via the proxy, sending an optional servername information [cn here]
    sock = context.wrap_socket(conn, server_hostname=cn)
    #retreive certificate from the server
    certificate = ssl.DER_cert_to_PEM_cert(sock.getpeercert(True))
    return certificate
于 2021-03-18T21:29:49.543 回答