Lean on SSLContext to do HTTPS hostname verification
See original GitHub issueIn Python 3.4 and 2.7.9 there is a check_hostname attribute on SSLContext which will have the SSLContext instance handle checking the hostname inside of the do_handshake. I think it would be good for urllib3 to rely on this where possible instead of doing the check itself. I think this would go good with the other efforts to use SSLContext as the “bag of configuration” for TLS stuff.
This can be detected by determining if the SSLContext object has a check_hostname attribute or not.
There is one downside, this relies on passing the hostname as part of SSLContext().wrap_socket(server_name=). Originally this only worked if the OpenSSL had SNI enabled. However Python 3.4.3 and 2.7.9 will accept server_name even if SNI isn’t enabled.
This would mean that the code a little ugly until you drop older versions of Python 3, it would look something like (paraphrased and super simplified to just be the ugly parts):
import ssl
import sys
# In reality these would use the SSLContext shim that urllib3 has in
# order to work on Python 2.6 too and 2.7 earlier than
if ssl.HAS_SNI or sys.version_info[0] == 2 or sys.version_info[:3] >= (3, 4, 3):
ctx = SSLContext(ssl.PROTOCOL_SSLv23)
ctx.check_hostname = True
sock = ctx.wrap_socket(sock, server_name="example.com")
else:
ctx = SSLContext(ssl.PROTOCOL_SSLv23)
sock = ctx.wrap_socket(sock)
if not ssl.match_hostname(sock.getpeercert(), "example.com"):
raise Error()
Maybe this is a bad idea? I think it would be great to lay the ground work for eventually moving the responsibility for checking hostnames into the stdlib, however you wouldn’t actually be able to do that completely without the ugly if statement until 3.4.3 was your minimum supports Python 3 version.
Issue Analytics
- State:
- Created 9 years ago
- Reactions:1
- Comments:16 (12 by maintainers)

Top Related StackOverflow Question
Talked with Seth and he’s worried that doing this later breaks weird use cases that call our internal but documented functions. So I’ll work on this as part of 2.0, not 2.x.
Another complication: pyOpenSSL only learned recently how to check hostnames in a simple way. But the release that includes that change also drops support for OpenSSL 1.0.2. So we’re also going to check hostnames manually with pyOpenSSL. And when we’ll drop support for OpenSSL 1.0.2, we’ll also require pyOpenSSL >= 20.0.0.
An additional complication is that
ssl.match_hostname()has been deprecated in Python 3.7+.