From f5faca9222541591e1a7c3c97552ebb0c92733c7 Mon Sep 17 00:00:00 2001 From: Jeremy Evans Date: Wed, 18 Sep 2024 14:11:49 -0700 Subject: [PATCH] Prevent request smuggling If a request has both a content-length and transfer-encoding headers, return a 400 response. This is allowed by RFC 7230 section 3.3.3.3. Fixes #145 --- lib/webrick/httprequest.rb | 4 ++++ test/webrick/test_httprequest.rb | 18 ++++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/lib/webrick/httprequest.rb b/lib/webrick/httprequest.rb index 527099f..0351a13 100644 --- a/lib/webrick/httprequest.rb +++ b/lib/webrick/httprequest.rb @@ -531,6 +531,10 @@ def parse_host_request_line(host) def read_body(socket, block) return unless socket if tc = self['transfer-encoding'] + if self['content-length'] + raise HTTPStatus::BadRequest, "request with both transfer-encoding and content-length, possible request smuggling" + end + case tc when /\Achunked\z/io then read_chunked(socket, block) else raise HTTPStatus::NotImplemented, "Transfer-Encoding: #{tc}." diff --git a/test/webrick/test_httprequest.rb b/test/webrick/test_httprequest.rb index ea7e5a9..d1283d4 100644 --- a/test/webrick/test_httprequest.rb +++ b/test/webrick/test_httprequest.rb @@ -219,6 +219,24 @@ def test_duplicate_content_length_header } end + def test_content_length_and_transfer_encoding_headers_smuggling + msg = <<~HTTP.gsub("\n", "\r\n") + POST /user HTTP/1.1 + Content-Length: 28 + Transfer-Encoding: chunked + + 0 + + GET /admin HTTP/1.1 + + HTTP + req = WEBrick::HTTPRequest.new(WEBrick::Config::HTTP) + req.parse(StringIO.new(msg)) + assert_raise(WEBrick::HTTPStatus::BadRequest){ + req.body + } + end + def test_parse_headers msg = <<~HTTP.gsub("\n", "\r\n") GET /path HTTP/1.1