Skip to content
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

Decode user and password from env configured proxy #5

Merged
merged 1 commit into from
Mar 8, 2021

Conversation

leipert
Copy link
Contributor

@leipert leipert commented Dec 30, 2020

If someone sets an env variable defining a http_proxy, containing a
username / password with percent-encoded characters, then the resulting
base64 encoded auth header will be wrong.

For example, suppose a username is Y\X and the password is R%S] ?X.
Properly URL encoded the proxy url would be:

http://Y%5CX:R%25S%5D%20%3FX@proxy.example:8000

The resulting proxy auth header should be: WVxYOlIlU10gP1g=, but the
getters defined by ruby StdLib URI return a username Y%5CX and
password R%25S%5D%20%3FX, resulting in WSU1Q1g6UiUyNVMlNUQlMjAlM0ZY.
As a result the proxy will deny the request.

Please note that this is my first contribution to the ruby ecosystem, to
standard lib especially and I am not a ruby developer.

Sorry for that and a happy and healthy 2021!

References:

@leipert leipert force-pushed the leipert-add-decoding-to-proxy-env branch 2 times, most recently from aab98eb to 8e3fcf0 Compare December 30, 2020 20:43
@leipert leipert force-pushed the leipert-add-decoding-to-proxy-env branch 2 times, most recently from 18ea109 to a698159 Compare February 3, 2021 14:22
@leipert
Copy link
Contributor Author

leipert commented Feb 3, 2021

Switched to using CGI.unescape over URI.decode_www_form_component as per:

https://gitlab.com/gitlab-org/gitlab/-/merge_requests/52368#note_500425249

@leipert
Copy link
Contributor Author

leipert commented Feb 3, 2021

@hsbt / @nobu Could either of you review this contribution? Thank you in advance 🙇

Have also created this issue in the bug tracker: https://bugs.ruby-lang.org/issues/17542

lib/net/http.rb Outdated
@@ -1180,7 +1180,8 @@ def proxy_port
# The username of the proxy server, if one is configured.
def proxy_user
if ENVIRONMENT_VARIABLE_IS_MULTIUSER_SAFE && @proxy_from_env
proxy_uri&.user
user = proxy_uri&.user
CGI.unescape(user) unless user.nil?
Copy link
Member

Choose a reason for hiding this comment

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

As cgi.rb isn't required here, it results in uninitialized constant Net::HTTP::CGI error.

Copy link
Member

Choose a reason for hiding this comment

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

And why unless user.nil? instead of if user?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@nobu Thanks for the review, changed it to if user and if pass respectively and added a require 'cgi' at the top.

Copy link
Member

Choose a reason for hiding this comment

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

Maybe require "cgi/escape" is enough?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@mame / @nobu Changed it to require "cgi/escape"!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Wouldn't it be require "cgi/util" though? And what is the difference between CGI::unescape and CGI.unescape

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed it to require "cgi/util". Hope that is alright.

Copy link
Member

Choose a reason for hiding this comment

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

As for method calls, :: and . are equivalent.
. seems preferred in these days though.

And, as CGI is used only when proxy env is given, it can be deferred to that cases only.

Copy link
Contributor Author

@leipert leipert Feb 9, 2021

Choose a reason for hiding this comment

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

Thank you @nobu. I don't understand the following aspect completely:

And, as CGI is used only when proxy env is given, it can be deferred to that cases only.

I don't know how the Ruby dependency loading works exactly (I was wondering that the tests didn't catch uninitialized constant Net::HTTP::CGI) you described in the first place.

Should I use autoload for the CGI module (autoload :CGI, 'cgi/util'), or should I potentially require it someplace else, for example in one of those places:

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@nobu Moved back to the . syntax and moved the require to the conditionals.

@leipert leipert force-pushed the leipert-add-decoding-to-proxy-env branch 4 times, most recently from c6899e4 to 5b57481 Compare February 6, 2021 10:03
lib/net/http.rb Outdated
Comment on lines 1184 to 1185
user = proxy_uri&.user
CGI::unescape(user) if user

Choose a reason for hiding this comment

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

Related to #5 (comment), I think they are referring to move the require 'cgi/util' L24 inside the conditions:

Suggested change
user = proxy_uri&.user
CGI::unescape(user) if user
user = proxy_uri&.user
if user
require 'cgi/util'
CGI::unescape(user)
end

Choose a reason for hiding this comment

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

An alternative to this is to extract a private method and re-use it in both places:

unescape(user) if user

private

def unescape(string)
  require 'cgi/util'
  CGI::unescape(string)
end

Copy link
Member

Choose a reason for hiding this comment

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

Related to #5 (comment), I think they are referring to move the require 'cgi/util' L24 inside the conditions:

I agree on this.

@leipert leipert force-pushed the leipert-add-decoding-to-proxy-env branch 2 times, most recently from 622e321 to 5d9ee8e Compare February 9, 2021 10:41
If someone sets an env variable defining a http_proxy, containing a
username / password with percent-encoded characters, then the resulting
base64 encoded auth header will be wrong.

For example, suppose a username is `Y\X` and the password is `R%S] ?X`.
Properly URL encoded the proxy url would be:

    http://Y%5CX:R%25S%5D%20%3FX@proxy.example:8000

The resulting proxy auth header should be: `WVxYOlIlU10gP1g=`, but the
getters defined by ruby StdLib `URI` return a username `Y%5CX` and
password `R%25S%5D%20%3FX`, resulting in `WSU1Q1g6UiUyNVMlNUQlMjAlM0ZY`.
As a result the proxy will deny the request.

Please note that this is my first contribution to the ruby ecosystem, to
standard lib especially and I am not a ruby developer.

References:

- https://gitlab.com/gitlab-org/gitlab/-/issues/289836
- https://bugs.ruby-lang.org/projects/ruby-master/repository/trunk/revisions/58461
- https://bugs.ruby-lang.org/issues/17542
@leipert leipert force-pushed the leipert-add-decoding-to-proxy-env branch from 5d9ee8e to a3b1b67 Compare February 17, 2021 10:17
@leipert
Copy link
Contributor Author

leipert commented Feb 17, 2021

@nobu / @mame I have moved the unescape and require to a private method. How do you feel about it?

Copy link
Contributor

@jeremyevans jeremyevans left a comment

Choose a reason for hiding this comment

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

I'm in favor of this change, and the implementation seems fine.

@jeremyevans jeremyevans merged commit e57d4f3 into ruby:master Mar 8, 2021
@leipert leipert deleted the leipert-add-decoding-to-proxy-env branch March 11, 2021 08:21
@leipert
Copy link
Contributor Author

leipert commented Mar 11, 2021

Thank you @nobu / @mame / @jeremyevans / @arturoherrero! 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants