-
Notifications
You must be signed in to change notification settings - Fork 29.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
http: create an option for setting a maximum size for uri parsing #26553
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If --max-http-uri-size
> --http-max-header-size
you'll never get a 414.
That's probably going to be surprising to some. I'm slightly -1 on adding a separate switch.
This comment has been minimized.
This comment has been minimized.
I think making it configurable makes sense. Apache uses the LimitRequestLine Directive for this. |
This comment has been minimized.
This comment has been minimized.
Yes, I agree on that. This is what this PR is addressing no? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure about the default value. Other than that LGTM.
Added semver-major because #25605 was also tagged as semver-major. |
Thank you. Would you be so kind to remove the merge commit? |
The http server wasn't able to tell exactly what caused an HPE_HEADER_OVERFLOW, meaning it would yield a 431 error even if what caused it was the request URI being too long. This adds a limit to the URI sizes through a new option called max-http-uri-size, which will be checked against the actual URIs after on_url callback at the node_http_parser_impl file. Fixes: nodejs#26296 Refs: expressjs/express#3898
test-http-header-overflow.js: the llhttp doesn't count space and separator, so to generate a breaking number of chars, just add +1 to the maxHeaderSize test-http-max-http-headers.js: remove the +1 that was referring to the slash of the uri, because it's not being counted anymore
ba4861e
to
38307dc
Compare
Unfortunately no. We had 80KB before and it was exploitable as a DoS vector https://nodejs.org/en/blog/vulnerability/november-2018-security-releases/#denial-of-service-with-large-http-headers-cve-2018-12121. I prefer a safe default. There is little difference in safety between 8KB and 16KB. |
I know URI !== URL but simplicity for the developer probably takes precedence over terminology precision. Since we use |
But the error that ends up being written is 414 URI Too Long. |
Not a bad point, but anything coming from the spec is going to say "URI" as the string "URL" does not appear at all in RFC 7231. But we're not going to change "url" to "uri" in our code base for any other options. So probably best to stick to one term when referring to the same thing. All that said, I'm fine if we decide to use "uri" here. Let's just make sure it's a considered decision and not an accidental inconsistency. |
Counting headers, URL and start lines separately because it was counting everything as headers before the headers_done state, throwing HPE_HEADER_OVERFLOW errors even when what really caused the overflow was the request URL being too long Creating an HPE_URL_OVERFLOW err to make sure embedders still have a request line limit, but now differentiating what went over such limit. Refs: nodejs/node#26553
@bnoordhuis that would render the "--http-max-header-size" option unable to limit the actual header size when using the legacy parser. Could you take a look at nodejs/http-parser#463? I splitted the counting there too, maybe that's better, considering we would only need to do something like this: const uint32_t max_http_uri_size =
per_process::cli_options->max_http_uri_size;
http_parser_set_max_uri_size(max_http_uri_size); and the options would work for both parsers after that @mcollina just to clear it up, are you talking about 16KB for headers and 8KB for url? @Trott I agree with you, there seems to be a preference for url over uri everywhere else in the code. |
|
||
* {number} | ||
|
||
Read-only property specifying the maximum allowed size of HTTP request uri |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Read-only property specifying the maximum allowed size of HTTP request uri | |
Read-only property specifying the maximum allowed size of HTTP request URI |
|
||
Read-only property specifying the maximum allowed size of HTTP request uri | ||
in bytes. Defaults to 7KB. Configurable using the | ||
[`--max-http-uri-size`][] CLI option. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing bottom references. Will this option be documented later?
I'm talking about 16KB total. I'd leave the division of those an implementation detail. If possible, I would limit the url to 7KB. I would also let headers use whatever is left in the "budget". |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This PR has changes specific to llhttp and http_parser. Can you add a test that exercise both paths?
// /, Host, localhost, Agent, node, X-CRASH, a... | ||
const currentSize = 1 + 4 + 9 + 5 + 4 + 7; | ||
// Host, localhost, Agent, node, X-CRASH, a... | ||
const currentSize = 4 + 9 + 5 + 4 + 7; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please explain this change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
currentSize is being used by fillHeaders
to subtract from the max header size and generate a header value with a length that makes the total header size hit the limit. Since the implementation at node_http_parser_impl.h when using llhttp doesn't count the url size towards the header size after the changes, there's no point considering the "/" size when using fillHeaders
anymore.
let received = ''; | ||
|
||
c.on('connect', mustCall(() => { | ||
c.write(PAYLOAD); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is highly possible that the payload comes out of the other side of the socket as a single Buffer. Can you please add a test where the URL is split into two or more chunks?
return maxHeaderSize - HEADER_NAME.length - HEADER_SEPARATOR - | ||
(2 * CRLF.length) + 1; | ||
} | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add some comments in this function?
@mcollina if we're updating the total request size to 16KB, perhaps we should conform with rfc7230 recommendation of |
Reference:
I looked, but not equivalent recommendation exists for header section as a whole, not that I found:
|
I'm cleaning out a few old PRs 🧹. I'm closing this due to inactivity. Please re-open if needed! |
I have been waiting on this PR to be merged. The --max-http-header-size flag does not seem to account for large uri strings. What is the suggested path forward for URI (with query parameters) that exceeds 8K? I am supporting a legacy system that sends very large form data URI parameters. |
@nodejs/http could use more reviews |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems mostly fine to me, but it definitely needs a rebase now that the legacy parser has been removed…
AddOption("--max-http-uri-size", | ||
"set the maximum size of HTTP request uri (default: 7KB)", | ||
&PerProcessOptions::max_http_uri_size, | ||
kAllowedInEnvironment); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fwiw, this should not be a per-process but rather a per-Environment option.
@Joshsteverson If you are invested in this PR, I think you can feel free to pick it up and open a new PR based on the code in this one. Usually, all that a PR needs to eventually land is an active author. |
8ae28ff
to
2935f72
Compare
Looks like this stalled out and would need to be updated in order for it to move forward. Closing but it can be reopened if someone wants to pick it back up. |
The http server wasn't able to tell exactly what caused an
HPE_HEADER_OVERFLOW, meaning it would yield a 431 error even if what
caused it was the request URI being too long.
This adds a limit to the URI sizes through a new option called
max-http-uri-size, which will be checked against the actual URIs
after on_url callback at the node_http_parser_impl file.
Fixes: #26296
Refs: expressjs/express#3898
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passes