-
Notifications
You must be signed in to change notification settings - Fork 377
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
Fix AppSec crash when parsing integer http headers #3790
Merged
vpellan
merged 4 commits into
master
from
vpellan/3782-appsec-crashes-when-parsing-integer-http-headers
Jul 24, 2024
+31
−1
Merged
Changes from 3 commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -41,7 +41,14 @@ def method | |||||
|
||||||
def headers | ||||||
result = request.env.each_with_object({}) do |(k, v), h| | ||||||
h[k.gsub(/^HTTP_/, '').downcase!.tr('_', '-')] = v if k =~ /^HTTP_/ | ||||||
# When multiple headers with the same name are present, they are concatenated with a comma | ||||||
# https://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.2 | ||||||
# Because headers are case insensitive, HTTP_FOO and HTTP_Foo is the same, and should be merged | ||||||
next unless k.start_with?('HTTP_') | ||||||
|
||||||
key = k.delete_prefix('HTTP_').tap(&:downcase!).tap { |s| s.tr!('_', '-') } | ||||||
current_val = h[key] | ||||||
h[key] = current_val.nil? ? v : "#{current_val}, #{v}" | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should work to transform an individual string for the single header case into an array, delegating the meaning of having multiple identical HTTP headers to whatever is downstream of the Reactive Engine.
Suggested change
|
||||||
end | ||||||
|
||||||
result['content-type'] = request.content_type if request.content_type | ||||||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
When could this happen?
HTTP_UPCASED_HEADER
key format.request.env.each_with_object
iterates on the rack env (which is a hash) there can be no duplicates except for mixed case, which cannot happen when Rack compliant due to the above.It follows that the only thing that could fill in some
HTTP_MiXeD_CaSe
is some non-Rack compliant middleware or monkeypatch that inject pseudo headers that actually don't exist on the HTTP request AND would execute before Datadog's middlewares, which are designed to be run first at the top of the Rack stack.According to the HTTP spec concatenation MAY happen but MUST only happen for headers that are lists. As is this code does so for ALL headers so it's very much incorrect, and possibly prone to injections or opportunities for a WAF bypass (e.g
Authorization
headers being concatenated in a way that make it valid for libddwaf rules but would in isolation - as seen by the application - be dangerous)I'm OK with making code robust in face of strange stuff, but trying to make sense of hypothetical non-compliant nonsense can only lead to problems (GIGO), therefore I question the cost of bearing the handling of these hypothetical use cases on every request.
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 agree that this is an extremely rare edge case, that would be introduced by some sort of weird middleware, and I believe that we should not be responsible for a client modifying the core behaviour of Rack, especially when it is only hypothetical. And a quick benchmark shows that this is 50x slower than your first suggestion with a bit of modification (replacing gsub by delete_prefix and regex in condition by start_with), which I believe is more important for our clients.