python http代理支持 https
首先需要2个软件来抓包。
fiddler : http 代理软件可以分析,抓包,重放。
wireshark : 全能抓包分析软件。
RFC 提供了非常好的设计描述。
https://tools.ietf.org/html/rfc7230
https://tools.ietf.org/html/rfc7231
安装好
Fiddler2
Tools ->Fiddler Options…-> Connections
Allow remotecomputers toconnect
需要重启 Fiddler2 后生效
Wireshark
设置好抓包规则
tcp.port == 8888
全部设置好后,使用另外一台电脑,配置好浏览器,打开下面的测试地址:
https://www.baidu.com/img/bd_logo1.png
最好是,在2台电脑上进行,有IP 地址比较好分辩(没有2台电脑的用VM 也行)。
本机为 192.168.1.127 , Fiddler 为 192.168.1.121。
可以看到,本地在发送了一个 请求头后,直接和 192.168.1.121 进行了 TLS 协商。
可见 HTTPS 代理也是非常容易实现。
TCP 流:
或者使用 curl 进行测试,firefox 自带了很多垃圾请求,不太好分辨包。
可见 百度用的是 apache 的服务器。
建立一个 连接到目标站点的 https socket。
回复 HTTP/1.1 200 Connection Established
浏览器发过来 client hello ,转发给 https socket
普通的 HTTP 是 请求 响应模式。
而 HTTPS 是有可能 HTTPS 也会主动发送 tcp 数据包过来,如 server hello 。
所以实现上,还需要用到 select 来实现 fd 的检查工作。
1 #!/usr/bin/env python 2 #coding:utf-8 3 import socket 4 import sys 5 import re 6 import os 7 import time 8 import select 9 import threading 10 11 HEADER_SIZE = 4096 12 13 host = '0.0.0.0' 14 port = 8000 15 16 #子进程进行socket 网络请求 17 def http_socket(client, addr): 18 #创建 select 检测 fd 列表 19 inputs = [client] 20 outputs = [] 21 remote_socket = 0 22 print("client connent:{0}:{1}".format(addr[0], addr[1])) 23 while True: 24 readable, writable, exceptional = select.select(inputs, outputs, inputs) 25 try: 26 for s in readable: 27 if s is client: 28 #读取 http 请求头信息 29 data = s.recv(HEADER_SIZE) 30 if remote_socket is 0: 31 #拆分头信息 32 host_url = data.split("\r\n")[0].split(" ") 33 method, host_addr, protocol = map(lambda x: x.strip(), host_url) 34 #如果 CONNECT 代理方式 35 if method == "CONNECT": 36 host, port = host_addr.split(":") 37 else: 38 host_addr = data.split("\r\n")[1].split(":") 39 #如果未指定端口则为默认 80 40 if 2 == len(host_addr): 41 host_addr.append("80") 42 name, host, port = map(lambda x: x.strip(), host_addr) 43 #建立 socket tcp 连接 44 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 45 sock.connect((host, int(port))) 46 remote_socket = sock 47 inputs.append(sock) 48 if method == "CONNECT": 49 start_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time())) 50 s.sendall("HTTP/1.1 200 Connection Established\r\nFiddlerGateway: Direct\r\nStartTime: {0}\r\nConnection: close\r\n\r\n".format(start_time)) 51 continue 52 #发送原始请求头 53 remote_socket.sendall(data) 54 else: 55 #接收数据并发送给浏览器 56 resp = s.recv(HEADER_SIZE) 57 if resp: 58 client.sendall(resp) 59 except Exception as e: 60 print("http socket error {0}".format(e)) 61 62 #创建socket对象 63 http_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 64 try: 65 http_server.bind((host, port)) 66 except Exception as e: 67 sys.exit("python proxy bind error {0}".format(e)) 68 69 print("python proxy start") 70 71 http_server.listen(1024) 72 73 while True: 74 client, addr = http_server.accept() 75 http_thread = threading.Thread(target=http_socket, args=(client, addr)) 76 http_thread.start() 77 time.sleep(1) 78 79 #关闭所有连接 80 http_server.close() 81 print("python proxy close")