[Python-Dev] PEP 476: Enabling certificate validation by default! (original) (raw)

Nick Coghlan ncoghlan at gmail.com
Mon Sep 1 08:05:18 CEST 2014


On 1 September 2014 11:10, R. David Murray <rdmurray at bitdance.com> wrote:

It sounds like this would address my concerns as well (I don't really care how it is implemented as long as I don't have to touch the code of a third party application when I upgrade my python version to 3.5...remember, the context here is backward compatibility concerns). Does it address the issue of accepting an invalid cert, though?

That's actually an interesting question, as the PEP doesn't currently propose adding any new global configuration knobs to the ssl or httplib modules - it just proposes switching httplib from the legacy (but fully backwards compatible) ssl._create_stdlib_context() API to the newer (but potentially backwards incompatible in some environments) ssl.create_default_context() API.

Having the ssl module import an sslcustomize module at the end wouldn't be enough unless the appropriate APIs were put in place to allow things to be configured at a process global level.

One possible way to do that would be to provide a central context factory mapping that provide a module specific SSL context creator. We'd seed it appropriately for the stdlib modules where we wanted to use the legacy context definition, but it would default to using ssl.create_default_context.

Under that kind of model, the first change we would actually make is to make ssl._create_stdlib_context() public under a suitable name, let's say ssl.create_legacy_context()

Independenting of any other changes, exposing ssl.create_legacy_context() like that would also make it straightforward for folks to opt in to the old behaviour as an interim hack in a way that is easy to grep for and fix later (it's also something a linter can easily disallow).

The second change would be to provide a mapping from arbitrary names to context factories in the ssl module that defaults to ssl.create_default_context:

named_contexts = defaultdict((lambda name: create_default_context))

(A more accurate name would be "named_context_factory", but I think "named_contexts" reads better. Folks will learn quickly enough that it actually stores context factories rather than prebuilt context objects)

The third change would be to replace all calls to "ssl._create_stdlib_context()" with calls to "ssl.named_contextsname" instead.

The final change would be to seed the context factory map appropriately for the standard library modules where we wanted to keep the old default:

for modname in ("nntplib", "poplib", "imaplib", "ftplib",

"smtplib", "asyncio.selector_events", "urllib.request", "http.client"): named_contexts[modname] = create_legacy_context

The list I have above is for all current uses of "sss._create_stdlib_context". The backwards incompatible part of PEP 476 would then just be about removing names from that list (currently just "http.client", but I'd suggest "asyncio.selector_events" as another candidate, taking advantage of asyncio's provisional API status).

The "revert to 3.4 behaviour" content for sslcustomize.py would then just be:

import ssl
ssl.named_contexts["http.client"] = ssl.create_legacy_context

However, someone that wanted to also enforce SSL properly for other standard library modules could go the other way:

import ssl
for modname in ("nntplib", "poplib", "imaplib", "ftplib",

"smtplib", "urllib.request"): ssl.named_contexts[modname] = ssl.create_default_context

Cheers, Nick.

-- Nick Coghlan | ncoghlan at gmail.com | Brisbane, Australia



More information about the Python-Dev mailing list