Skip to content
This repository was archived by the owner on Sep 30, 2024. It is now read-only.

fix/internal/requestclient: read all instances of x-forwarded-for header, not just the first#64137

Merged
ggilmore merged 1 commit intomainfrom
graphite-ggilmorefix_internal_requestclient_read_all_instances_of_x-forwarded-for_header_not_just_the_first
Jul 30, 2024
Merged

fix/internal/requestclient: read all instances of x-forwarded-for header, not just the first#64137
ggilmore merged 1 commit intomainfrom
graphite-ggilmorefix_internal_requestclient_read_all_instances_of_x-forwarded-for_header_not_just_the_first

Conversation

@ggilmore
Copy link
Contributor

@ggilmore ggilmore commented Jul 29, 2024

Closes https://linear.app/sourcegraph/issue/SRC-454/extract-and-propagate-user-ip-address-throughout-the-request-lifecycle

According to HTTP1.1/RFC 2616: Headers may be repeated, and any comma-separated list-headers (like X-Forwarded-For) should be treated as a single value.

In section 4.2:

Multiple message-header fields with the same field-name MAY bepresent in a message if and only if the entire field-value for that header field is defined as a comma-separated list [i.e., #(values)]. It MUST be possible to combine the multiple header fields into one"field-name: field-value" pair, without changing the semantics of the message, by appending each subsequent field-value to the first, each separated by a comma. The order in which header fields with the same field-name are received is therefore significant to the interpretation of the combined field value, and thus a proxy MUST NOT change the order of these field values when a message is forwarded.

For Example:

For the following HTTP request, it's valid to have multiple instances of x-forwarded-for:

Header Name Header Value
X-Forwarded-For 203.0.113.195, 70.41.3.18
X-Forwarded-For 150.172.238.178
X-Forwarded-For 123.45.67.89
... ...

That must be interpret-able as X-Forwarded-For: 203.0.113.195, 70.41.3.18, 150.172.238.178, 123.45.67.89

Previously, our code used http.Header.Get():

https://github.com/sourcegraph/sourcegraph/blob/9e26623d90461bf7df2e0f3e35561fecc0c35f3f/internal/requestclient/http.go#L81-L95

However, func (Header) Get only returns the first value of the header:

Get gets the first value associated with the given key. If there are no values associated with the key, Get returns "". ...

In our example, this means that our code would only get X-Forwarded-For: 203.0.113.195, 70.41.3.18, which is invalid according to RFC 2616.

Test plan

There were no unit tests, so I added some.

Changelog

@cla-bot cla-bot bot added the cla-signed label Jul 29, 2024
@github-actions github-actions bot added team/product-platform team/source Tickets under the purview of Source - the one Source to graph it all labels Jul 29, 2024
Copy link
Contributor Author

ggilmore commented Jul 29, 2024

@ggilmore ggilmore marked this pull request as ready for review July 29, 2024 20:34
@ggilmore ggilmore force-pushed the graphite-ggilmorefix_internal_requestclient_read_all_instances_of_x-forwarded-for_header_not_just_the_first branch from 1a5c8ba to df474fa Compare July 29, 2024 20:36
Copy link
Contributor Author

@ggilmore ggilmore Jul 29, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I got rid of external boolean here since we only ever took action if both it and useCloudflareHeaders were true. We simplify the logic here by just moving this logic to the Internal/External middleware constructors.

@ggilmore ggilmore requested a review from a team July 29, 2024 21:07
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume CF prevents anyone from adding this header, or it makes sure that the header they set is always first?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://developers.cloudflare.com/fundamentals/reference/http-request-headers/#x-forwarded-for

I haven't tested this personally, but the way I interpret their docs is that they assume responsibility for preventing anyone from being able to set this header:

CF-Connecting-IP provides the client IP address connecting to Cloudflare to the origin web server. This header will only be sent on the traffic from Cloudflare’s edge to your origin web server.

@eseliger

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for tests!

@ggilmore ggilmore force-pushed the graphite-ggilmorefeat_worker_permission_syncing_make_sub_repo_permissions_re-insertion_fall_back_to_original_paths_if_ips_not_added_yet branch from 9e26623 to 62d9ad8 Compare July 29, 2024 22:11
@ggilmore ggilmore force-pushed the graphite-ggilmorefix_internal_requestclient_read_all_instances_of_x-forwarded-for_header_not_just_the_first branch from df474fa to 415e9b2 Compare July 29, 2024 22:12
Copy link
Contributor Author

ggilmore commented Jul 30, 2024

Merge activity

  • Jul 30, 10:40 AM EDT: @ggilmore started a stack merge that includes this pull request via Graphite.
  • Jul 30, 11:10 AM EDT: Graphite rebased this pull request as part of a merge.
  • Jul 30, 11:15 AM EDT: Graphite couldn't merge this PR because it was not satisfying all requirements (Failed CI: 'buildkite/sourcegraph', 'check').

@ggilmore ggilmore changed the base branch from graphite-ggilmorefeat_worker_permission_syncing_make_sub_repo_permissions_re-insertion_fall_back_to_original_paths_if_ips_not_added_yet to graphite-base/64137 July 30, 2024 14:42
@ggilmore ggilmore changed the base branch from graphite-base/64137 to main July 30, 2024 15:07
@ggilmore ggilmore force-pushed the graphite-ggilmorefix_internal_requestclient_read_all_instances_of_x-forwarded-for_header_not_just_the_first branch from 415e9b2 to 5499193 Compare July 30, 2024 15:09
@github-actions
Copy link
Contributor

Caution

License checking failed, please read: how to deal with third parties licensing.

@ggilmore ggilmore merged commit 7a3da57 into main Jul 30, 2024
@ggilmore ggilmore deleted the graphite-ggilmorefix_internal_requestclient_read_all_instances_of_x-forwarded-for_header_not_just_the_first branch July 30, 2024 15:35
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

cla-signed team/product-platform team/source Tickets under the purview of Source - the one Source to graph it all

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants