Skip to content

Implement X-Forwarded-For header processing #7359

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

Merged
merged 4 commits into from
Oct 26, 2023

Conversation

Turbo87
Copy link
Member

@Turbo87 Turbo87 commented Oct 25, 2023

This PR essentially implements http://nginx.org/en/docs/http/ngx_http_realip_module.html inside of our axum server, as another step towards removing the nginx wrapper.

… but there is a twist. Heroku is somewhat broken. Their broken handles the header incorrectly in case the original request contains multiple X-Forwarded-For headers. Instead of adding the connecting IP to the last header, or merging the headers, it adds the IP to the first header 😱

I've reported this to Heroku in the form of a support ticket, but while that is being processed we will unfortunately have to use a workaround. Luckily CloudFront merges these headers, so if we get multiple headers we can know for certain that the request did not come from CloudFront.

On the bright side, we only use the value for logging at the moment. The PR adds another field to the logs with the IP addressed that was parsed from the X-Forwarded-For headers. It also adds a log marker in case the IP is different from the one that nginx supplies us in the X-Real-IP header. This will allow us to see if there are differences to the nginx algorithm once production traffic hits this code. Spoiler alert: yes, the Heroku workaround is a difference, but for regular, non-malicious traffic this should not matter.

@Turbo87 Turbo87 added C-internal 🔧 Category: Nonessential work that would make the codebase more consistent or clear A-backend ⚙️ labels Oct 25, 2023
This adjusts the `process_xff_headers()` to our current deployment reality of the app being reachable either directly on Heroku or with CloudFront in front. It also adds a work around for some broken Heroku behavior.
…eader values

This is supposed to eventually replace the `X-Real-IP` header usage once production traffic has shown that our implementation is correct.
Copy link

@walterhpearce walterhpearce left a comment

Choose a reason for hiding this comment

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

Mainly, two major comments:

  • String comparisons on a flat vec for something per-request is very slow, it'd be beneficial to use cidr in an appropriate integer-sized hashmap for lookups.
  • Should we even allow direct calls via heroku, or should we just start banishing all requests not using a CDN?

@Turbo87
Copy link
Member Author

Turbo87 commented Oct 26, 2023

Since this is purely additive and the performance concerns have been addressed, I'll go ahead and merge this to test it out on staging and then deploy it to production.

@Turbo87 Turbo87 merged commit 2da2fc6 into rust-lang:main Oct 26, 2023
@Turbo87 Turbo87 deleted the xff-madness branch October 26, 2023 08:13
Comment on lines +168 to +169
// The Heroku router has a bug where it currently (2023-10-25) appends
// the connecting IP to the **first** header instead of the last.
Copy link
Member Author

Choose a reason for hiding this comment

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

for context: heroku/roadmap#238

@Turbo87 Turbo87 mentioned this pull request Oct 26, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-backend ⚙️ C-internal 🔧 Category: Nonessential work that would make the codebase more consistent or clear
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants