[Python-Dev] PYTHONHTTPSVERIFY env var

M.-A. Lemburg mal at egenix.com
Tue May 12 09:57:32 CEST 2015

On 12.05.2015 05:03, Nick Coghlan wrote:
> On 12 May 2015 at 04:49, M.-A. Lemburg <mal at egenix.com> wrote:
>> On 11.05.2015 12:15, Nick Coghlan wrote:
>>> By contrast, the configuration file shouldn't provide a new attack
>>> vector (or simplify any existing attack vector), as if you have the
>>> permissions needed to modify the config file, you likely also have the
>>> permissions needed to modify the system certificate store, and the
>>> latter is a *far* more interesting attack vector than a downgrade
>>> attack solely against Python.
>>> Thus the environment variable based off switch is neither necessary
>>> (as an administrator controlled configuration file can do the job),
>>> nor sufficient (it can't handle the -E switch), *and* it represents an
>>> increase in the attack surface area relative to a Python
>>> implementation without the capability.
>> Whether or not -E will have an effect on the env var depends
>> on the implementation. At the moment, -E only has an effect
>> on the C runtime, while the stdlib happily reads from os.environ
>> without taking the flag into account.
> I had an off-list discussion with Christian Heimes about that in
> relation to the OpenSSL flags, and he pointed out the reason -E
> specifically needs to be a command line switch is because that is the
> only way to affect how environment variables are processed during
> interpreter startup. Once an application is up and running, further
> environment variable sanitisation can be handled at an application
> level by whitelisting entries in os.environ and deleting everything
> else.
>> As proposed, the PYTHONHTTPSVERIFY would only affect the ssl
>> module and only be checked when loading this module, i.e. not
>> at Python startup time.
> Right, the same is true for the configuration file proposal.
>>> It would be nice to hear from ActiveState, Enthought & Continuum
>>> Analytics as well, but if they don't chime in here, I don't see any
>>> particular need to go chasing them explicitly.
>> I think the approach to only consider a subset of redistributors
>> as viable targets for such a switch is a bit too narrow.
>> You are leaving out all the parties which use custom
>> Python installations to run their applications, e.g.
>> the Plone and Zope community, the ZenOSS community,
>> the many Windows applications built on Python, etc.
> No, they already have a solution: monkeypatch (or just plain patch)
> the SSL module. That's an upstream supported technique, which is why
> it's documented in the PEP.

Again, this is not a proper solution for your friendly
sys admin. They won't go in and patch Python, but rather
consider it broken, if it doesn't provide a configuration
option and simply stay with 2.7.8.

We've had that discussion already, so I won't go into details

> The problem we (as in Red Hat) ran into was that that technique
> *doesn't work* for the case of backporting PEP 476 to Python 2.7.5 as
> an opt-in feature.

And neither does it work for people deploying Windows apps
built on Python (where the code is usually hidden away
in a ZIP archive or even compiled into a DLL), or people
deploying Plone or ZenOSS.

It's not only Red Hat's customers that are affected :-)

>>>> to fix this regression in 2.7.9.
>>> We made the decision when PEP 476 was accepted that this change turned
>>> a silent security failure into a noisy one, rather than being a
>>> regression in its own right. PEP 493 isn't about disagreeing with that
>>> decision, it's about providing a smoother upgrade path in contexts
>>> where letting the security failure remain silent is deemed to be
>>> preferred in the near term.
>> The change wasn't regression. The missing downgrade path
>> is a regression.
> It's a shame we don't have "-X" options in Python 2, as that would be
> a nice hard-to-attack option (although it wouldn't play well with
> subprocesses)
>> Some other comments on PEP 493:
>> * I don't think we really want to add the overhead of
>>   having to parse an INI file every time Python starts up.
>>   Please remember that we just parsing of the sysconfig
>>   data not long ago because we wanted to avoid this startup
>>   time.
> Compared to the overhead of reading from the system cert database,
> reading a config file at ssl module import time should be trivial.

The cert database is only read when importing the ssl
module, not with each Python startup, so that makes a
big difference.

The INI file would have to parsed at ssl module load time
as well to work around this.

>> * I don't see why the attack surface of using an INI file
>>   somewhere in the system should be smaller than e.g. using
>>   sitecustomize.py
> You can put sitecustomize.py in a user directory, and if there's no
> system wide sitecustomize, Python will read it automatically (unless
> user site directories are turned off).

In a user based installation (which most applications shipping
their own Python installation are), you can always do this
provided you can gain the application user permissions.

For a system installed Python, you'd always have to run
Python with -E -S -s to avoid this, but then you'd also
loose the system wide site-packages dir, so I'm not sure
whether that's really an option.

>> * If done right, we'd also need a switch to ignore this
>>   global config file and recommend using it to reduce the
>>   attack surface (for the same reason you explain in the
>>   PEP)
> No, the recommendation there would be to upgrade to a newer version of
> Python that doesn't offer this downgrade capability. It's a proposal
> for a transition smoothing technique, not a permanent capability (I
> did suggest the latter at one point, but the discussion on the issue
> tracker persuaded me that was a bad idea, with the increased attack
> surface being a key part of that change of heart).

You mean the config file approach would only exist for
Python 2.7 ?

>> * I don't think a global switch is the right way forward.
>>   Many applications on properly configured systems will
>>   work fine with the new default. The downgrade option is
>>   only needed for those cases, where they don't and you
>>   don't have a good way to fix the application.
> And techniques like chroots and containers let you do that selectively.

Nick, I lost you there.

Are you suggesting that sys admins who want to upgrade to Python 2.7.9
and need the downgrade option should put the whole application
into a container to work around a design deficiency in the
downgrade option ?

> The key thing I'm after is an agreed technique for backporting to
> earlier 2.7.x releases that allows PEP 476 to be provided as an opt-in
> capability, rather than gating it on folks upgrading to 2.7.9, which
> isn't going to happen for *years* in a great many environments (Ubuntu
> 14.04 LTS, for example, doesn't go end of life until 2019 and ships
> 2.7.6 + non-intrusive security patches, while RHEL 7 doesn't go end of
> life until 2024 and ships 2.7.5 + compatible backports that address
> customer problems).
> While other Linux vendors have currently decided to leave the HTTPS
> problem unfixed in their long term support releases (due to the risk
> of causing service failures in customer environments), I'm hoping they
> may revisit those decisions if there's a specific technique already
> agreed with upstream for backporting the capability in a way that
> makes it an opt-in feature that customers can switch on independently
> of the inclusion of the feature backport in the system Python.

Again, you're only seeing Red Hat's customers as target for
this. Not everyone in this world runs on Red Hat, even
if you'd probably like that :-)

OS distributions can easily patch their system Python
as needed.

The point here is that sys admins should not
have to patch Python to make things work again, in case
an application is not prepared for the certificate
verification - which is rather likely, since the pre-Python
2.7.9 doesn't even provide the necessary APIs to pass
certificate locations to urllib or urllib2.

>> * Most applications use some kind of virtualenv
>>   Python environment to run the code. These are
>>   typically isolated from the system Python installation
>>   and so wouldn't want to use a system wide global INI
>>   neither.
> Having a separate configuration setting that controls verification in
> virtual environments is a good idea. That could also provide the
> per-application opt-out capability that you're after.

The env var would already enable virtualenv to set this up
automatically, without any local config file.

To cover all the different cases, you will inevitably have to
provide a system wide config file, a user one and a local one,
just like we have for distutils:


>> * The -S switch completely disables importing site.py.
>>   That's not really a viable solution in the age of
>>   pip - your local installation wouldn't find the installed
>>   packages anymore, since these are installed in site-packages/
>>   which again, is set up by site.py.
> Yes, getting an administrative application to the point where -S can
> be used means getting it to a point where it has *no* Python
> dependencies outside the standard library. It can certainly be done,
> but often won't be worth the hassle. As a result, using -s to turn off
> the user site directory and -E to turn off PYTHONPATH processing are
> the more common sys.path related hardening techniques in Python 2.7.

Overall, I find the config file approach a too big a hammer to solve
this simple problem.

If there were more use cases for a Python config file, the added
overhead could pay off, but then we should put more thought into
optimizing the config file load time and probably end up using
a Python module as config file (which provides these optimizations
for free).

In the end, we'd be introducing another sitecustomize.py,
usercustomize.py and perhaps localcustomize.py - only with
fixed locations rather than importing them via sys.path.

Marc-Andre Lemburg

Professional Python Services directly from the Source  (#1, May 12 2015)
>>> Python Projects, Coaching and Consulting ...  http://www.egenix.com/
>>> mxODBC Plone/Zope Database Adapter ...       http://zope.egenix.com/
>>> mxODBC, mxDateTime, mxTextTools ...        http://python.egenix.com/

::::: Try our mxODBC.Connect Python Database Interface for free ! ::::::

   eGenix.com Software, Skills and Services GmbH  Pastor-Loeh-Str.48
    D-40764 Langenfeld, Germany. CEO Dipl.-Math. Marc-Andre Lemburg
           Registered at Amtsgericht Duesseldorf: HRB 46611

More information about the Python-Dev mailing list