oven-sh / bun

Incredibly fast JavaScript runtime, bundler, test runner, and package manager – all in one
https://bun.sh
Other
74.25k stars 2.77k forks source link

Bun.serve not answers when HTTP header name contains underscore #3580

Closed krutoo closed 9 months ago

krutoo commented 1 year ago

What version of Bun is running?

0.6.13

What platform is your computer?

Darwin 22.1.0 arm64 arm

What steps can reproduce the bug?

  1. create index.ts with content:
    Bun.serve({
    port: 1234,
    fetch() {
    return new Response('Hello, world!');
    },
    });
  2. bun run index.ts
  3. Make http request (for example via Postman) with header foo-bar_baz: 1.2.3

What is the expected behavior?

postman get an answer Hello, world!

What do you see instead?

Postman cannot receive response - it freezes on stage "Sending request..."

When i remove this custom header it works perfectly

Additional information

According to this resource: https://www.rfc-editor.org/rfc/rfc9110.html#fields.registry

header names should contains only

- alphanumeric characters
- "."
- "-"

Maybe it is reason why Bun.serve() not anwsers on requests with headers with underscore

krutoo commented 1 year ago

@uNetworkingAB but I didn't claim anything =)

Jarred-Sumner commented 1 year ago

If we were to add support for this in uWebSockets, I think it'd mean changing these lines:

cc @kwhitley

nickpalmer commented 1 year ago

I'm not concerned about it accepting the header or not, but about it hanging if you pass such a header. That is a potential Denial Of Service vector.

If the header isn't valid the server should maybe emit a 409 return code instead of hanging. Alternatively it could just close the connection, but a 409 would at least give consumers an indication something is wrong.

That said, most implementations don't validate incoming headers and just pass them on to the application to decide about. Be lenient in what you accept and all that.

Jarred-Sumner commented 1 year ago

I'm not concerned about it accepting the header or not, but about it hanging if you pass such a header. That is a potential Denial Of Service vector.

If the header isn't valid the server should maybe emit a 409 return code instead of hanging. Alternatively it could just close the connection, but a 409 would at least give consumers an indication something is wrong.

That said, most implementations don't validate incoming headers and just pass them on to the application to decide about. Be lenient in what you accept and all that.

It treats it the same as other forms of invalid input. It keeps the connection open until a timeout elapses, doesn’t send more data and halts parsing. This is cheap so it’s not likely to be a DoS vector

kwhitley commented 1 year ago

It treats it the same as other forms of invalid input. It keeps the connection open until a timeout elapses, doesn’t send more data and halts parsing. This is cheap so it’s not likely to be a DoS vector

How do other http servers handle something like this? I know nginx, for instance, just ignores those headers... but I would assume in the case of a bad/malformed request, that an error response (e.g. 400?) would be appropriate, rather than a live/stalled connection with no feedback.

dszymon commented 10 months ago

@Jarred-Sumner the issue is really important for user-facing services. Right now a website created with Bun doesn't pass LinkedIn Inspector due to headers formatted like X-LI-R2-W-IC-2-com.linkedin.container.dsc: 1

uNetworkingAB commented 9 months ago

https://github.com/uNetworking/uWebSockets/releases/tag/v20.60.0

uNetworkingAB commented 9 months ago

That said, most implementations don't validate incoming headers and just pass them on to the application to decide about. Be lenient in what you accept and all that.

This literally is request smuggling and allows to bypass proxies. That's why the validation must be strict.

I'm not concerned about it accepting the header or not, but about it hanging if you pass such a header. That is a potential Denial Of Service vector.

It's not a DOS vector since the entire HTTP standard is based on accepting anything until you reach CRLFCRLF so the very same behavior of waiting until timeout can be seen for regular use. You get the same exact behavior if you just send the letter "H" and wait until timeout. This is the case for all HTTP servers in existence 😉