-
Notifications
You must be signed in to change notification settings - Fork 521
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
Allow redirecting to another host to download package. #2803
Conversation
This is essentially removing all TLS checks and is a bad idea for security. That check makes sure that the certificate chain matches the domain requested in the query in the CA bundle we have. Rebar3 supports mirrors or private registries that are layered, and will seek any package, through all of them, in order until they eventually hit a registry with the package they want. The hash version from the lock file will determine whether the registry has the proper package version, and signatures will be compared to make sure the proper copy is the one being fetched. You can see what a configuration for this looks like in
Pretty much all fields there are optional so you can put in your own, and can be specified in the You can also use these options to use private organizations on hex, or to publish to various repos with distinct keys (see https://hexdocs.pm/rebar3_hex/rebar3_hex_organization.html for these points). I realize now that https://hex.pm/docs/rebar3-private alludes to this functionality, but does not explain how to make it work. |
Hey @ferd, thanks for taking the time to comment. Despite the somewhat missing documentation, I did manage to figure out, largely through reading the code, how to configure rebar3 to make uploading and downloading work. Where I am struggling, specifically, is in this hostname check. Rebar3 doesn't seem to want to deal with a 302 redirect in the same way that any other package manager client is doing today. If the change I am proposing removes all TLS checks, is there another way to reconfigure this part of the code to allow 302s to another domain (for package download), while still maintaining the checks that keep the client secure? |
I'd need to see the request and the domain going there, but that check fails specifically when doing a TLS call and getting a certificate for the wrong domain name. If the endpoint that does the 302 redirection serves the proper cert (or one that is not self-signed), then it should be okay. But if what you have is something like:
These can all fail validation checks. Removing the domain check, no matter what you do, essentially says "let any man-in-the-middle respond with whatever they want here, don't check that they are who I expect them to be." I don't really know what other package managers are doing, but if they let you 302 with the wrong certs, they're either dangerous, or they use another signing mechanism with known keys inside the protocol do an extra layer of validation. We can also do the latter, but safer TLS validation isn't a bad thing. I can possibly help debug the specific chain of calls you want to happen, but I'll probably want more details about the operations and the domains that this goes through. I don't think "just don't check TLS, it works elsewhere" is workable because it absolutely depends on where and how the internal protocols are doing further checks for trust. |
Curious what |
I guess one issue would be that the redirect is to a distinct domain but the check remains on the same one as well. |
@ferd I believe this is what is happening.
A possible solution could be to change |
than the original URI. Previously, we were checking all redirected URIs against the original hostname, which failed when a redirect was sent to a new host.
4d57f7a
to
a2e73bb
Compare
Updated this PR with a POC for that approach. This doesn't disable any checks, but handles redirects manually. I have tested this and it also serves to fix the redirect issue. (Although it is incomplete in its handling of 3xx responses) I'm not really convinced that this is the solution though. More just trying to push the conversation forward. |
I do believe this is a better approach than disabling checks altogether yeah. The other option would be to modernize validation. I think the current validation function was added in R15, way before OTP had any mechanism for TLS validation. Starting in OTP-21, we can pass something like this:
to httpc options to get cert validation going. Starting with OTP-25, we can use the OS's store for CA certs, but I think we can start relying on this in one major version (starting with OTP-27). Then starting with OTP-26 (which we can use starting in OTP-28), the checks are done by default. https://erlef.github.io/security-wg/secure_coding_and_deployment_hardening/inets has the details on what to do here. Chances are that right now we can use the public_key validation check and keep passing in our certifi CA bundle. It might work better for the redirect mechanism without erroring out. |
While investigating the work required to support erlang#2803, I found out that the code was already in place. However, despite the code being there, we still passed the old `ssl_verify_hostname:verify_fun/3` function of pre-21.0 on top of it, which I supposed ignored the check. So this change reworks the flow such that we fall back to the legacy check only if it isn't supported by the OTP library at this point. Getting this going would require someone to build a new release on an Erlang copy older than OTP-21 (which is no longer supported) which is unlikely. This follows guidelines from https://erlef.github.io/security-wg/secure_coding_and_deployment_hardening/ssl
Closing in favour of #2805 |
I am currently developing a private registry. It was already working with Mix, but uploading and consuming packages with Rebar3 has been a challenge. I have got uploading working with a PR to rebar3_hex, and this PR is intended to address difficulties with downloading a package using rebar3.
My package registry works by validating that the user may access the package version they are attempting to access, and then sending a 302 directing the client to my CDN, with a signed URL. This currently fails at the "check_hostname" step, since rebar3 attempts to verify that the hostname matches the original (pre-redirect) URL. (I am redirecting from codecodeship.com to a "shared" domain on Fastly.)
I have "fixed" this issue by simply removing the
check_hostname
option from the SSL verify function. I will admit right away that I am not sure of the further security implications of this change. But it seems like this is locking the request to just the originally requested hostname, and blocking redirects to other hostnames outright. I know (from watching Bram Verburg speak a number of times) that SSL handling is a minefield.What I can tell you for certain is that every other package manager I have implemented so far is handling this case out of the box with no issues (Hex, NPM, Cargo, RubyGems, Nuget).
Your feedback is appreciated.