-
Notifications
You must be signed in to change notification settings - Fork 19
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
Enhance security by removing Authorization header on HTTP redirects #36
Conversation
773e6cb
to
133b678
Compare
370d5d1
to
b7d6496
Compare
b7d6496
to
8c0cf68
Compare
Rebased with master branch |
@akr Thank you very much for your maintenance efforts. When you have time, could you review this PR? |
@akr Sorry to bother you while you're busy. If there is any missing information or unclear parts that would help in reviewing this PR, please let me know. I’m more than happy to prepare for anything needed to assist with the review. |
I understand the motivation. We need to customize header fields for each request. However, I feel that hard coding the field name "Authorization" is not a good idea. How about adding a keyword argument to specify request-specific header fields?
The hash specifies the header fields only before redirecting. Note that the argument can be extended with procedures.
The procedure is called for each request and returns additional header fields for the request. |
@akr Thank you for explaining the proposed method to customize header fields for each request using a hash or a block. I think the policy to allow customizable headers is a great approach. Could you help me clarify the specification about the following points? Specify a HashWhen we pass a hash as Specify a BlockRegarding the use of a block, does the library evaluate this block with the new URL for each request, allowing for dynamic header customization at every step of the request process, including during multiple redirections? Please let me know if my understanding is incorrect. Thank you for helping me. Additionally, I have a suggestion regarding the default behavior for the "Authorization" header. Could you share your thoughts on this? Suggestion about the Default Behavior for "Authorization" HeaderConsidering that users might not always remember to specify the "Authorization" header explicitly in request_specific_fields, do you think it would be beneficial to have a default implementation that automatically excludes this header from subsequent requests? This could prevent potential security issues by ensuring sensitive headers are not inadvertently sent across redirects unless explicitly included by the user. If a user wishes to customize this behavior further, they could override this default implementation by specifying |
Your understanding of "Specify a Hash" and "Specify a Block" is correct. I don't accept 'Suggestion about the Default Behavior for "Authorization" Header'. If such a mechanism is introduced in open-uri, someone may report that some fields (such as "Cookie" field) are not treated like "Authorization" field as a security problem. |
Thank you for clarifying the specification. I also understand your decision not to introduce the default behavior for the With that in mind, I will proceed to implement |
This commit introduces the `request_specific_fields` option in OpenURI. It provides two methods for customizing headers as follows. 1. Specify headers only for the initial request Use a Hash to apply headers only to the first request. These headers are automatically removed during redirects. 2. Specify headers dynamically for each request Use a Proc to dynamically generate headers for each request, including during redirects, based on the request URL. This feature allows users to control headers flexibly, ensuring that sensitive headers like "Authorization" are not unintentionally transferred during redirects unless explicitly specified.
8c0cf68
to
2e7734c
Compare
@akr Could you please review the implementation to ensure it meets our specifications? |
lib/open-uri.rb
Outdated
|
||
if options.has_key? :request_specific_fields | ||
if !(options[:request_specific_fields].is_a?(Hash) || options[:request_specific_fields].is_a?(Proc)) | ||
raise ArgumentError, "Invalid request_specific_fields' format: #{options[:request_specific_fields]}" |
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 think "format" is not an appropriate word here.
Also, inspect
should be called for the option value to show it for users.
So, how about making the exception message
"Invalid request_specific_fields: #{options[:request_specific_fields].inspect}"?
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.
fix f89ce51:
Thanks you so much. I completely agree with your suggestion. Adding inspect will indeed provide users with more detailed information when debugging.
I also added the word option to the message to maintain consistency with other option-related error messages.
Added `inspect` to the `request_specific_fields` value to provide better visibility for users in the exception message.
When redirects occur, the Authorization header containing authorization information is transferred to the redirect destination host. This can expose sensitive credentials to unintended hosts, posing a security risk.
I will introduce a case where the Authorization header is unintentionally transferred during redirection.
Case
The issue occurs when downloading GitHub Actions Artifacts using the GitHub REST API.
The process is as follows.
During the redirect in step 2, the Authorization header from step 1 is retained and transferred to the redirect destination.
This results in an authorization error due to the redirection destination misinterpreting the Authorization header content as the SAS.
Reproduce code
Here is a Ruby code example that demonstrates the problem, resulting in a 403 error because the Authorization header does not match the expected signature format.
Workaround
When redirecting without transferring the Authorization header content, the download succeeds without errors.
This means the Authorization header is retained during redirects.
Expected Improvement
We aim to improve security by removing the Authorization header during redirects if necessary, preventing its inadvertent transfer to the redirect destination host.
The Fetch specification recommends removing the Authorization header on cross-origin redirects.
Supplemental Information
Examples of software or specifications that do not transfer the Authorization header on redirect:
Curl
Curl does not transfer the Authorization header on redirects and this issue is reported as a CVE.
GO
Go removes the Authorization header when redirecting to different hosts but retains it if the redirect is to the same host.
Proposed Solutions
To address the
Expected Improvement
mentioned above and to ensure future flexibility for handling headers beyond just the Authorization header, we propose introducing a customizable solution that allows users to define their own header-handling rules. This approach ensures that users can manage which headers are retained or removed during redirects, providing a flexible and secure implementation.To provide this customization feature, we introduce the
request_specific_fields
option. This option offers two methods for handling headers as follows:Specify headers for the initial request (Using a
Hash
)Users can specify request specific headers for the initial request via a
Hash
.These headers will only be applied to the first request and automatically removed on redirects.
Specify headers for each request (Using a
Proc
)For more dynamic control, users can define a
Proc
that generates headers based on the URL of each request.The Proc is evaluated for every request, including those made during redirects, allowing for flexible header management throughout the request lifecycle.
By implementing the
request_specific_fields
option in this way, we provide flexibility without hardcoding sensitive fields like the "Authorization" header. Users maintain full control over which headers are sent with each request, allowing them to exclude sensitive headers during redirects if desired. This solution keeps OpenURI secure by design while offering customizable behavior when needed.