拦截来自浏览器python的https流量

2024-04-26 22:36:33 发布

您现在位置:Python中文网/ 问答频道 /正文

因此,我试图创建一个web代理来拦截浏览器流量,但是使用http很容易,我也可以很容易地做到,但是当涉及到https时,我得到了这个非信息性错误,我不知道是什么错了,我所能找到的是,当执行这一行时会触发异常(client_socket, address) = ssl_socket.accept()

import socket
import thread
import ssl

def proxy_server():
    server_scoket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    # http_listener(server_scoket)
    https_listener(server_scoket)
    # server_scoket.close()




def https_listener(server_scoket):
    ssl_socket = ssl.wrap_socket(server_scoket,keyfile='localhost.key',certfile='localhost.crt',server_side=1)
    ssl_socket.bind(('127.0.0.1',9000))
    ssl_socket.listen(50)
    while True:
        try :
            (client_socket, address) = ssl_socket.accept()

            thread.start_new_thread(proxy_thread, (client_socket, address))
        except Exception as e:
            print "Error {}".format(e)

为了测试代码,我尝试浏览python网站:www.python.org,下面是输出:

Error [SSL: HTTPS_PROXY_REQUEST] https proxy request (_ssl.c:727)

更新1: 完整代码:

import socket
import thread
import ssl

def proxy_server():
    server_scoket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    http_listener(server_scoket)
    # https_listener(server_scoket)
    # server_scoket.close()




def https_listener(server_scoket):
    context = ssl.SSLContext(ssl.PROTOCOL_TLS)
    context.load_cert_chain('localhost.crt', 'localhost.key')
    server_scoket.bind(('127.0.0.1',9000))
    server_scoket.listen(5)
    ssl_socket = context.wrap_socket(server_scoket,server_side=True)
    while True:
        try :
            (client_socket, address) = ssl_socket.accept()
            thread.start_new_thread(proxy_thread, (client_socket, address))
        except Exception as e:
            print "Error {}".format(e)

def http_listener(server_scoket):
    try :

        server_scoket.bind(('127.0.0.1',9000))
        server_scoket.listen(50)

        while True:

            (client_socket, address) = server_scoket.accept()
            thread.start_new_thread(proxy_thread, (client_socket, address))



    except KeyboardInterrupt :
        print "\n shutting down"
    except Exception as e :
        print "Error : {}".format(e)

def proxy_thread(connection, client_address):

    request = connection.recv(5000)
    url     = request.split('\n')[0].split(' ')[1] 
    splited_request = request.split('\r\n\r\n')
    headers = splited_request[0].split('\n')
    body    = splited_request[1]
    port    = 0
    print "---------"
    print request
    print "---------"
    splitted_url = url.split(':')
    url  = splitted_url[1][2:]
    base_url = url.split('/')[0] 
    path_url = url[len(base_url):]

    if (len(splitted_url) < 3):
        port = 80
    else:
        port = splitted_url[2]

    try :

        splited_line = headers[0].split(' ')
        if (splited_line[0] != "CONNECT"):
            headers[0] = "{} {} {}".format(splited_line[0],path_url,splited_line[2])
        else:
            base_url = headers[0].split(' ')[1]
        new_headers = ""
        for index,header in enumerate(headers) :
            if (index != len(headers) - 1): 
                headers[index] = "{}\n".format(header)
        new_headers = "".join(headers)
        request = "{} \r\n\r\n {}".format(new_headers,body)

        if (splitted_url[0] == "https"):
            https_proxy(base_url,443,request,connection)
        else:
            http_proxy(base_url,443,request,connection)


        connection.close()
    except OSError,  message:
        if s:
            s.close()
        if connection:
            connection.clos()
        print "Error messgae : "+ message

    except Exception as e:
        print "Error : {}".format(e)

def http_proxy(base_url,port,request,connection):
    print "------ http request start -----"
    print request
    print "------ request ends -----"
    print port
    if(request.split(' ')[0] == 'CONNECT'):
                reply = "HTTP/1.1 200 OK\r\n\r\n"
                connection.sendall(reply)
                print request.split(' ')[0]
                print "replied HTTP/1.1 200 OK\r\n\r\n"
                return
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.connect((base_url,port))
    s.sendall(request)

    while True:
        data = s.recv(50000)
        if (len(data) > 0):
            connection.sendall(data)
        else:
            break
    s.close()


def https_proxy(base_url,port,request,connection):
    print "------ https request start -----"
    print request
    print "------ request ends -----"
    print port

    sp_base_url = base_url.split(':')
    base_url = sp_base_url[0] if len(sp_base_url) > 1 else base_url

    context = ssl.create_default_context()
    sock = socket.create_connection(("cdn.sstatic.net",443))
    print port
    context.load_verify_locations('/etc/ssl/certs/ca-certificates.crt')
    ssock = context.wrap_socket(sock, server_hostname="cdn.sstatic.net")
    print ssock.version()
    ssock.sendall(request)
    while True:
        data = ssock.recv(5000)
        if (len(data) > 0):
            print data
            connection.sendall(data)
        else:
            break

    sock.close()
    connection.close()
print "You can use the following proxy : \n host : 127.0.0.1 \n port : 9000 \n"
proxy_server()

执行输出:

You can use the following proxy : 
 host : 127.0.0.1 
 port : 9000 

---------
CONNECT www.pythonconverter.com:443 HTTP/1.1
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0
Proxy-Connection: keep-alive
Connection: keep-alive
Host: www.pythonconverter.com:443


---------
------ http request start -----
CONNECT www.pythonconverter.com:443 HTTP/1.1
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0
Proxy-Connection: keep-alive
Connection: keep-alive
Host: www.pythonconverter.com:443 


------ request ends -----
443
CONNECT
replied HTTP/1.1 200 OK

但从我的理解来看,我应该从浏览器获得一个新的连接,或者至少在同一个套接字上获得一个请求,但是这不会发生


Tags: httpsurlsslbaseserverportrequestsocket