denoland / deno

A modern runtime for JavaScript and TypeScript.
https://deno.com
MIT License
98.22k stars 5.41k forks source link

HTTP server does not validate `Host` header is present #26554

Open uNetworkingAB opened 1 month ago

uNetworkingAB commented 1 month ago

Version: Deno 2.0.0

I made a quick and simple standards test and found that Deno does not properly check for Content-Length vs. Transfer-Encoding. It must close the connection with error if both headers are present.

Also, the Host header is not checked.

Screenshot 2024-10-25 222602

littledivy commented 1 month ago

re request smuggling the spec says:

https://datatracker.ietf.org/doc/html/rfc7230#section-3.3.3

If a message is received with both a Transfer-Encoding and a Content-Length header field, the Transfer-Encoding overrides the Content-Length. Such a message might indicate an attempt to perform request smuggling (Section 9.5) or response splitting (Section 9.4) and ought to be handled as an error. A sender MUST remove the received Content-Length field prior to forwarding such a message downstream.

Deno correctly overrides the Content-Length header field when calling the request handler.

Deno.serve((req) => {
    console.log(req.headers)
})
Headers { host: "example.com", "transfer-encoding": "chunked" }

Although I don't really like this and it should just close connection with error.

uNetworkingAB commented 1 month ago

Ah, fair enough.

But Host is missing:

A server MUST respond with a 400 (Bad Request) status code to any HTTP/1.1 request message that lacks a Host header field [...]

littledivy commented 1 month ago

Opened https://github.com/hyperium/hyper/issues/3777

uNetworkingAB commented 1 month ago

You're right, Deno does override Content-Length properly now that I updated the test. The only failure is re. Host header now.

✅ Overflowing negative Content-Length header: Response Status Code 400, Expected ranges: [[400,499]] ✅ Conflicting Transfer-Encoding and Content-Length in varying case: Response Status Code 200, Expected ranges: [[400,499],[200,299]] ✅ Request without HTTP version: Response Status Code 400, Expected ranges: [[400,599]] ✅ Invalid header characters: Response Status Code 400, Expected ranges: [[400,499]] ✅ Negative Content-Length header: Response Status Code 400, Expected ranges: [[400,499]] ✅ Non-numeric Content-Length header: Response Status Code 400, Expected ranges: [[400,499]] ✅ Header containing invalid control character: Response Status Code 400, Expected ranges: [[400,499]] ✅ Invalid HTTP version: Response Status Code 400, Expected ranges: [[400,499],[500,599]] ✅ Invalid prefix of request: Response Status Code 400, Expected ranges: [[400,499],[500,599]] ✅ Invalid line ending: Response Status Code 400, Expected ranges: [[400,499]] ✅ Request with Expect header: Response Status Code 200, Expected ranges: [[100,100],[200,299]] ✅ Valid GET request: Response Status Code 200, Expected ranges: [[200,299]] ✅ Valid GET request with edge cases: Response Status Code 200, Expected ranges: [[200,299]] ❌ Missing Host header: Response Status Code 200, Expected ranges: [[400,499]] ❌ Multiple Host headers: Response Status Code 200, Expected ranges: [[400,499]] ✅ Empty header value: Response Status Code 200, Expected ranges: [[200,299]] ✅ Valid POST request with body: Response Status Code 200, Expected ranges: [[200,299],[404,404]] ✅ Chunked Transfer-Encoding: Response Status Code 200, Expected ranges: [[200,299]] ✅ Fragmented HTTP version: Server waited successfully ✅ Fragmented field value 1: Server waited successfully ✅ Fragmented method: Server waited successfully ✅ Fragmented URL 1: Server waited successfully ✅ Fragmented URL 2: Server waited successfully ✅ Fragmented URL 3: Server waited successfully ✅ Fragmented request line: Server waited successfully ✅ Fragmented request line newline 1: Server waited successfully ✅ Fragmented request line newline 2: Server waited successfully ✅ Fragmented field name: Server waited successfully ✅ Fragmented field value 2: Server waited successfully ✅ Fragmented field value 3: Server waited successfully ✅ Fragmented field value 4: Server waited successfully ✅ Fragmented request: Server waited successfully ✅ Fragmented request termination: Server waited successfully

31 out of 33 tests passed.