-
-
Notifications
You must be signed in to change notification settings - Fork 9.3k
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
Don't use pyOpenSSL unless no SNI is detected #5443
Conversation
I think this looks pretty straight forward and I agree we want to start moving away from PyOpenSSL by default. The only Python versions we'd expect to still be using pyopenssl after this would be <2.7.9, right? I'm think I'm fine approving but would like a second peek from Tiran or @sigmavirus24 if possible. As for |
I already have the name registered FYI: https://pypi.org/project/requests-security-extra Something like: try:
import requests_security_extra
warnings.warn(
"Installing 'requests[security]' is deprecated and will be removed in a future version of Requests. "
"After changing your pip installs to remove [security] you can run "
"'python -m pip uninstall requests-security-extra' to silence this DeprecationWarning",
category=DeprecationWarning
)
except ImportError:
pass |
What I'll also say if we don't necessarily need to deprecate the extra since the worst that happens with the latest pip if the dist doesn't include the extra you asked for is to warn the user. So maybe that isn't as necessary as I originally thought? |
So if we're doing better feature detection of the cases when we need to inject PyOpenSSL, why break backwards compatibility by removing This was never meant to be a perfect solution, it was just the best solution within the constraints of an art project that reluctantly tried to be secure. I fear y'all will have more headaches trying to remove this than not and your ability to have a functioning inbox is important to me (and it should be important to you too) |
@sigmavirus24 That's true, we can keep the extra as-is. As far as this patch looks now though you're in favor? Can definitely add a changelog entry. |
The proposed PR is a good compromise between backwards compatibility and my requested change. My main pain point was the fact that requests changed behavior depending on the presence of a 3rd party package and that PyOpenSSL is not compatible with W^X memory protection of modern CPUs. How about documenting |
That seems like a great idea. By that point Requests should also just be supporting something like 3.6+ or 3.7+ so there should be no reason for PyOpenSSL (ideally 🤞 )
Right, last night I fell asleep wondering "Why does @tiran even care? No one does |
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.
One question but otherwise LGTM
# Check cryptography version | ||
from cryptography import __version__ as cryptography_version | ||
_check_cryptography(cryptography_version) | ||
# Check cryptography version |
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.
GitHub is rendering this oddly. Is this a tab or some kind of mixed white space?
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.
That is a strange render but as far as I can tell they're all spaces.
I care because PyOpenSSL doesn't play nice with security hardening and The main system stacks at $JOB includes a Python webservice that runs on Apache and mod_wsgi. An SELinux policy prevents Apache to create memory pages with mmap that are both writeable and executable. In general it's a terrible idea because it allows an attacker to run arbitrary native code easily. This all works fine with default set of packages that do not include PyOpenSSL. But some $CUSTOMERS also install additional packages. One of the packages depends on PyOpenSSL. As soon as PyOpenSSL is present and Apache is restarted, requests starts to behave differently, triggers SELinux violations, and the main API service is broken. The Apache service often runs for days, weeks or longer without restart. There is no apparent causation between the problem and PyOpenSSL. First time we had a lot of "fun" figuring out the cause of the problem... I came up with this workaround: freeipa/freeipa@dea059d |
@tiran Yikes! 😱 |
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.
Ok cool, it sounds like we’ve got agreement this is a decent compromise to at least get us moving in the right direction.
Actually can we get a quick change log added for this too, @sethmlarson? |
@nateprewitt Sure thing, it'll be done in half an hour. :) |
@nateprewitt Done, let me know if you want to change the verbage. |
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.
Perfect 👌
Thanks all for the reviews! 🎉 |
I just wanted to let you know that I am using PyOpenSSL integration not because of Python 2 issues but because the ability to use client-side keys and certificates provided as raw bytes instead of files (via https://www.pyopenssl.org/en/stable/api/ssl.html#OpenSSL.SSL.Context.use_certificate and https://www.pyopenssl.org/en/stable/api/ssl.html#OpenSSL.SSL.Context.use_privatekey) which seems to be difficult otherwise. |
@saper Thanks for bringing that use-case to my attention! If you still need pyOpenSSL support you can manually call |
@sethmlarson Yes, this is what I ultimately did because I only had Time to pin the dependencies I guess :/ Big thanks for documenting it clearly here though - once I realized the release was out 6 hours earlier I figured it out very quickly. |
You can load certs and keys from a raw bytes with Python's ssl module, too. Just dump them into a temporary directory, load them from file, and remove the directory after you have loaded the files. Python ensures that a temporary directory is only accessible by the current effective user. This makes the approach safe. There is no risk when the key is secured with PKCS#8 PBE2. There is a minimal risk if the key is not encrypted, you are running multiple untrusted processes under the same EUID and you have partly hardened the system. You can mitigate the risk by implementing privilege separation. In all other cases loading private keys from raw bytes is less secure than loading it from files! OpenSSL does a far better job than Python when it comes to managing and cleaning memory that holds sensitive data. Just consider this example:
|
@tiran Sure, I know I can't trust anything like Python too much. I am not sure I always have a writable filesystem and other things (just being fed with PKCS#12 files). For proper key security I'd need to go the PKCS#11 route, but that has other issues (like poor library support). |
Remove no longer needed patches: Don-t-inject-pyopenssl-into-urllib3.patch: psf/requests#5443 requests-2.20.0-no-py2-httpbin.patch: python2-requests is no more anyway
For some reason the ssl module is hitting an infinite recursion error. This might be CircleCI-specific, depending on the openssl lib they used to compile python. The 3.7.0 version is supposed to be even more robust, so it could also be something about v3.6.13. I have not reproduced the error elsewhere, however. The error began appearing after we updated requests from v2.23.0 to v2.25.1 in StackStorm/st2#5215 In requests v2.24.0, it defaulted to using the python ssl module instead of PyOpenSSL due to various SELinux issues. Before that it used PyOpenSSL whenever it was installed. Since it worked with pyopenssl, we just revert to using it for the tests in this repo. See: psf/requests#5443
For some reason the ssl module is hitting an infinite recursion error. This might be CircleCI-specific, depending on the openssl lib they used to compile python. The 3.7.0 version is supposed to be even more robust, so it could also be something about v3.6.13. I have not reproduced the error elsewhere, however. The error began appearing after we updated requests from v2.23.0 to v2.25.1 in StackStorm/st2#5215 In requests v2.24.0, it defaulted to using the python ssl module instead of PyOpenSSL due to various SELinux issues. Before that it used PyOpenSSL whenever it was installed. Since it worked with pyopenssl, we just revert to using it for the tests in this repo. See: psf/requests#5443
This is part 1 on removing
requests[security]
extra, for now we can still support SNI-less installations of Python but instead of unconditional monkey-patching we only patch if we detect either nossl
module or noSNI
support.Related: #5267
cc @tiran
An additional thought I had was if we wanted to warn users about the complete removal of
requests[security]
I don't think there's a way to detect if you were installed viarequests pyopenssl
orrequests[security]
beyond registering a name on PyPI likerequests-security-extra
, trying to import it, and if we do then we know we were installed viarequests[security]
so throw a deprecation warning? Otherwise our "end-goal" could be to haverequests[security]
be empty?