[Python-Dev] PEP 466 (round 3): Python 2 network security enhancements (original) (raw)
Nick Coghlan ncoghlan at gmail.com
Mon Mar 24 14:43:29 CET 2014
- Previous message: [Python-Dev] cpython: #20145: assert[Raises|Warns]Regex now raise TypeError on bad regex.
- Next message: [Python-Dev] PEP 466 (round 3): Python 2 network security enhancements
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
And time for round 3 :)
Notable changes:
- removed the higher level networking modules from the scope of the PEP. They made people nervous, and aren't actually needed to achieved the desired result (at the higher levels, it's much easier for third party pure Python modules like requests to step in and fill the gap, as long as the core SSL infrastructure has been updated)
- dropped the sha module from the exemption and explicitly noted that both the sha and md5 modules have been deprecated since Python 2.5
- conditional exemptions are now only granted for things that the security infrastructure depends on, rather than the other way around
- answered the OpenSSL question based on MAL and Ned's feedback
- added the "2.7-legacy-ssl" branch to the proposal (along with some pointed comments about the development priorities implied by preferring this branch to the one with the improved security infrastructure)
- made it even clearer that I consider the situation commercial redistributor's responsibility to clean up, based on the support commitments they have made to their users. The PEP is primarily about changing one specific aspect of our maintenance policies so that the onus is clearly pushed back on them to fill the gap between what their customers want and what upstream volunteers are prepared to do for free - we shouldn't give them the opportunity to hide behind the excuse that we won't let them fix it upstream.
Cheers, Nick.
==================================== PEP: 466 Title: Network Security Enhancement Exception for Python 2.7 Version: RevisionRevisionRevision Last-Modified: DateDateDate Author: Nick Coghlan <ncoghlan at gmail.com>, Status: Draft Type: Informational Content-Type: text/x-rst Created: 23-Mar-2014 Post-History: 23-Mar-2014
Abstract
Most CPython tracker issues are classified as errors in behaviour or proposed enhancements. Most patches to fix behavioural errors are applied to all active maintenance branches. Enhancement patches are restricted to the default branch that becomes the next Python version.
This cadence works reasonably well during Python's normal 18-24 month feature release cycle, which is still applicable to the Python 3 series. However, the age of the standard library in Python 2 has now reached a point where it is sufficiently far behind the state of the art in network security protocols for it to be causing real problems in commercial use cases where upgrading to Python 3 in the near term may not be practical.
Accordingly, this PEP relaxes the normal restrictions by allowing enhancements to be applied in Python 2.7 maintenance releases for standard library components that have implications for the overall security of the internet. In particular, the exception will apply to:
- the
ssl
module - the
hashlib
module - the
hmac
module - the components of the
random
andos
modules that the above modules rely on for cryptographic randomness - the version of OpenSSL bundled with the binary installers for Windows and Mac OS X
Changes to these modules will still need to undergo normal backwards compatibility assessments, but otherwise they will be kept entirely aligned with the latest feature release of their Python 3 counterparts. This is designed to make it easier to implement secure networked software in Python, even for software that currently needs to remain compatible with the Python 2 series (which includes a lot of network infrastructure software).
The development branches will be arranged in such a way that even though any further Python 2.7 releases published by the core development team provide updated network security infrastructure, it will remain possible for downstream redistributors to publish "Python 2.7 with legacy SSL infrastructure" if they choose to do so.
While this PEP does not make any changes to the core development team's handling of security-fix-only branches that are no longer in active maintenance, it does recommend that commercial redistributors providing extended support periods for the Python standard library either adopt a similar approach to ensuring that the secure networking infrastructure keeps pace with the evolution of the internet, or else disclaim support for the use of older versions in roles that involving connecting directly to the public internet.
Exemption Policy
Under this policy, the following network security related modules are granted a blanket exemption to the restriction against adding new features in maintenance releases, for the purpose of keeping their APIs aligned with their counterparts in the latest feature release of Python 3:
- the
ssl
module - the
hashlib
module - the
hmac
module
This exemption applies to all proposals to backport backwards compatible changes in these modules to Python 2.7 maintenance releases. This choice is made deliberately to ensure that the "feature or fix?" argument isn't simply replaced by a "security related or not?" argument. These particular modules are inherently security related, and all enhancements to them improve Python's capabilities as a platform for development of secure networked software.
As part of this policy, permission is also granted to upgrade to newer feature releases of OpenSSL when preparing the binary installers for new maintenance releases of CPython.
Note that the sha
and md5
modules are not covered by this policy,
but have been deprecated in favour of hashlib
since Python 2.5 and have
been removed entirely in the Python 3 series.
In addition to the above blanket exemption, a conditional exemption is granted for these modules that may include some network security related features:
- the
os
module (specificallyos.urandom
) - the
random
module
This more limited exemption for these modules requires that the specific enhancement being proposed for backporting needs to be justified as being network security related. This is generally restricted to cases where the feature in question is needed by an update to one of the modules covered by the blanket exemption.
Backwards Compatibility Considerations
This PEP does not grant any general exemptions to the usual backwards compatibility policy for maintenance releases. Instead, by explicitly encouraging the use of feature based checks and explicitly opting in to less secure configurations, it is designed to make it easier to provide more "secure by default" behaviour in future feature releases, while still limiting the risk of breaking currently working software when upgrading to a new maintenance release.
In all cases where this policy is applied to backport enhancements to maintenance releases, it MUST be possible to write cross-version compatible code that operates by "feature detection" (for example, checking for particular attributes in the module), without needing to explicitly check the Python version.
It is then up to library and framework code to provide an appropriate warning and fallback behaviour if a desired feature is found to be missing. While some especially security sensitive software MAY fail outright if a desired security feature is unavailable, most software SHOULD instead emit a warning and continue operating using a slightly degraded security configuration.
Affected APIs SHOULD be designed to allow library and application code to perform the following actions after detecting the presence of a relevant network security related feature:
- explicitly opt in to more secure settings (to allow the use of enhanced security features in older maintenance releases of Python)
- explicitly opt in to less secure settings (to allow the use of newer Python feature releases in lower security environments)
- determine the default setting for the feature (this MAY require explicit Python version checks to determine the Python feature release, but MUST NOT require checking for a specific maintenance release)
Security related changes to other modules (such as higher level networking
libraries and data format processing libraries) will continue to be made
available as backports and new modules on the Python Package Index, as
independent distribution remains the preferred approach to handling
software that must continue to evolve to handle changing development
requirements independently of the Python 2 standard library. Refer to
the Motivation and Rationale
_ section for a review of the characteristics
that make the secure networking infrastructure worthy of special
consideration.
OpenSSL compatibility
Under this policy, OpenSSL may be upgraded to more recent feature releases in Python 2.7 maintenance releases. On Linux and most other POSIX systems, the specific version of OpenSSL used already varies, as Python dynamically links to the system provided OpenSSL library by default.
For the Windows binary installers, the _ssl
and _hashlib
modules are
statically linked with OpenSSL and the associated symbols are not exported.
Marc-Andre Lemburg indicates that updating to newer OpenSSL releases in the
egenix-pyopenssl
binaries has not resulted in any reported compatibility
issues [3]_
The Mac OS X binary installers historically followed the same policy as other POSIX installations and dynamically linked to the Apple provided OpenSSL libraries. However, Apple has now ceased updating these cross-platform libraries, instead requiring that even cross-platform developers adopt Mac OS X specific interfaces to access up to date security infrastructure on their platform. Accordingly, and independently of this PEP, the Mac OS X binary installers were already going to be switched to statically linker newer versions of OpenSSL [4]_
Other Considerations
Maintainability
This policy does NOT represent a commitment by volunteer contributors to actually backport network security related changes from the Python 3 series to the Python 2 series. Rather, it is intended to send a clear signal to potential corporate contributors that the core development team are willing to accept offers of corporate assistance in putting this policy into effect and handling the resulting increase in the Python 2 maintenance load.
Backporting security related fixes and enhancements to earlier versions is a common service for commercial redistributors to offer to their customers. This policy represents an explicit invitation to contribute some of those changes back to the upstream community in cases where they are likely to have a broad impact that helps improve the security of the internet as a whole, rather than sitting back and waiting for unpaid volunteers to do it for them.
Documentation
All modules covered by this policy MUST include a "Security Considerations" section in their documentation.
In addition to any other module specific contents, this section MUST enumerate key security enhancements and fixes (with CVE identifiers where applicable), along with the feature and maintenance releases that first included them.
Security releases
This PEP does not propose any changes to the handling of security releases - those will continue to be source only releases that include only critical security fixes.
However, the recommendations for library and application developers are deliberately designed to accommodate commercial redistributors that choose to apply this policy to additional Python release series that are either in security fix only mode, or have been declared "end of life" by the core development team.
Whether or not redistributors choose to exercise that option will be up to the individual redistributor.
Integration testing
Third party integration testing services should offer users the ability to test against both the latest Python 2.7 maintenance release and the latest "Python 2.7 with legacy SSL infrastructure" release, to ensure that libraries, frameworks and applications handle the legacy security infrastructure correctly (either failing or degrading gracefully, depending on the security sensitivity of the software).
Handling lower security environments with low risk tolerance
For better or for worse (mostly worse), there are some environments where the risk of latent security defects is more tolerated than the risk of regressions in maintenance releases. This policy largely excludes these environments from consideration where the modules covered by the exemption are concerned.
However, one concession is made for the benefit of such environments: while
the main 2.7
branch in Mercurial will include the updated network
security infrastructure, the development process will be updated to include
a 2.7-legacy-ssl
branch with the more limited feature set of the
original 2.7 network security infrastructure, allowing downstream
redistributors to continue to provide Python 2.7 with the legacy SSL
infrastructure if they choose to do so. This branch will be tested
on the CPython continuous integration infrastructure, but no releases will
be made from it by the core development team.
As noted above, corporate redistributors and users are expected to provide the additional development effort needed to make this practical. It is not acceptable to expect volunteer contributors to resolve a problem created largely by conservative corporate development practices.
Evolution of this Policy
The key requirement for a module to be considered for inclusion in this policy (whether under a blanket or conditional exemption) is that it must have security implications beyond the specific application that is written in Python and the system that application is running on. Thus the focus on network security protocols and related cryptographic infrastructure - Python is a popular choice for the development of web services and clients, and thus the capabilities of widely used Python versions have implications for the security design of other services that may themselves be using newer versions of Python or other development languages, but need to interoperate with clients or servers written using older versions of Python.
The intent behind this requirement is to minimise any impact that the introduction of this policy may have on the stability and compatibility of maintenance releases. It would be thoroughly counterproductive if end users became as cautious about updating to new Python maintenance releases as they are about updating to new feature releases.
Motivation and Rationale
This PEP can be seen as a more targeted version of the "faster standard library release cycle" proposals discussed in PEP 407 and PEP 413, focusing specifically on those areas which have implications beyond the Python community.
Background
The creation of this PEP was prompted primarily by the aging SSL support in the Python 2 series. As of March 2014, the Python 2.7 SSL module is approaching four years of age, and the SSL support in the still popular Python 2.6 release had its feature set locked six years ago.
These are simply too old to provide a foundation that can be recommended in good conscience for secure networking software that operates over the public internet, especially in an era where it is becoming quite clearly evident that advanced persistent security threats are even more widespread and more indiscriminate in their targeting than had previously been understood. While they represented reasonable security infrastructure in their time, the state of the art has moved on, and we need to investigate mechanisms for effectively providing more up to date network security infrastructure for users that, for whatever reason, are not currently in a position to migrate to Python 3.
While the use of the system OpenSSL installation addresses many of these concerns on Linux platforms, it doesn't address all of them, and in the case of the binary installers for Windows and Mac OS X that are published on python.org, the version of OpenSSL used is entirely within the control of the Python core development team, and currently limited to OpenSSL maintenance releases for the version initially shipped with the corresponding Python feature release.
With increased popularity comes increased responsibility, and this policy aims to acknowledge the fact that Python's popularity and adoption has now reached a level where some of our design and policy decisions have significant implications beyond the Python development community.
As one example, the Python 2 ssl
module does not support the Server
Name Identification standard. While it is possible to obtain SNI support
by using the third party requests
client library, actually doing so
currently requires using not only requests
and its embedded dependencies,
but also half a dozen or more additional libraries. The lack of support
in the Python 2 series thus serves as an impediment to making effective
use of SNI on servers, as Python 2 clients will frequently fail to handle
it correctly.
Another more critical example is the lack of SSL hostname matching in the
Python 2 standard library - it is currently necessary to rely on a third
party library, such as requests
or backports.ssl_match_hostname
to
obtain that functionality in Python 2.
The Python 2 series also remains more vulnerable to remote timing attacks
on security sensitive comparisons than the Python 3 series, as it lacks a
standard library equivalent to the timing attack resistant
hmac.compare_digest()
function. While appropriate secure comparison
functions can be implemented in third party extensions, may users don't
even consider the issue and use ordinary equality comparisons instead
- while a standard library solution doesn't automatically fix that problem, it does make the barrier to resolution much lower once the problem is pointed out.
My position on the ongoing transition from Python 2 to Python 3 has long been that Python 2 remains a supported platform for the core development team, and that commercial support will remain available well after upstream maintenance ends. However, in the absence of this network security enhancement policy, that position is difficult to justify when it comes to software that operates over the public internet. Just as many developers consider it too difficult to develop truly secure modern networked software in C/C++ (largely due to the challenges associated with manual memory management), I anticipate that in the not too distant future, it will be considered too difficult to develop truly secure modern networked software using the Python 2 series (some developers would argue that we have already reached that point).
Alternative: advise developers of networked software to migrate to Python 3
This alternative represents the status quo. Unfortunately, it has proven to be unworkable in practice, as the backwards compatibility implications mean that this is a non-trivial migration process for large applications and integration projects. While the tools for migration have evolved to a point where it is possible to migrate even large applications opportunistically and incrementally (rather than all at once) by updating code to run in the large common subset of Python 2 and Python 3, using the most recent technology often isn't a priority in commercial environments.
Previously, this was considered an acceptable harm, as while it was an unfortunate problem for the affected developers to have to face, it was seen as an issue between them and their management chain to make the case for infrastructure modernisation, and this case would become naturally more compelling as the Python 3 series evolved.
However, now that we're fully aware of the impact the limitations of the Python 2 standard library may be having on the evolution of internet security standards, I no longer believe that it is reasonable to expect platform and application developers to resolve all of the latent defects in an application's Unicode correctness solely in order to gain access to the network security enhancements already available in Python 3.
While Ubuntu (and to some extent Debian as well) are committed to porting all default system services and scripts to Python 3, and to removing Python 2 from its default distribution images (but not from its archives), this is a mammoth task and won't be completed for the Ubuntu 14.04 LTS release (at least for the desktop image - it may be achieved for the mobile and server images).
Fedora has even more work to do to migrate, and it will take a non-trivial amount of time to migrate the relevant infrastructure components. While Red Hat are also actively working to make it easier for users to use more recent versions of Python on our stable platforms, it's going to take time for those efforts to start having an impact on end users' choice of version, and any such changes also don't benefit the core platform infrastructure that runs in the integrated system Python by necessity.
The OpenStack migration to Python 3 is also still in its infancy, and even though that's a project with an extensive and relatively robust automated test suite, it's still large enough that it is going to take quite some time to migrate.
And that's just three of the highest profile open source projects that make heavy use of Python. Given the likely existence of large amounts of legacy code that lacks the kind of automated regression test suite needed to help support a migration from Python 2 to Python 3, there are likely to be many cases where reimplementation (perhaps even in Python 3) proves easier than migration. The key point of this PEP is that those situations affect more people than just the developers and users of the affected application: the existence of clients and servers with outdated network security infrastructure becomes something that developers of secure networked services need to take into account as part of their security design, and that's a problem that inhibits the adoption of better security standards.
As Terry Reedy noted, if we try to persist with the status quo, the likely outcome is that commercial redistributors will attempt to do something like this on behalf of their customers anyway, but in a potentially inconsistent and ad hoc manner. By drawing the scope definition process into the upstream project we are in a better position to influence the approach taken to address the situation and to help ensure some consistency across redistributors.
The problem is real, so something needs to change, and this PEP describes my currently preferred approach to addressing the situation.
Alternative: create and release Python 2.8
With sufficient corporate support, it likely would be possible to create and release Python 2.8 (it's highly unlikely such a project would garner enough interest to be achievable with only volunteers). However, this wouldn't actually solve the problem, as the aim is to provide a relatively low impact way to incorporate enhanced security features into integrated products and deployments that make use of Python 2. Upgrading to a new Python feature release would mean both more work for the core development team, as well as a more disruptive update that most potential end users would likely just skip entirely.
Attempting to create a Python 2.8 release would also bring in suggestions
to backport many additional features from Python 3 (such as tracemalloc
and the improved coroutine support), making the migration from Python 2.7
to this hypothetical 2.8 release even riskier and more disruptive.
This is not a recommended approach, as it would involve substantial additional work for a result that is actually less effective in achieving the original aim (which is to eliminate the current widespread use of the aging network security infrastructure in the Python 2 series).
Alternative: distribute the security enhancements via PyPI
While this initially appears to be an attractive and easier to manage approach, it actually suffers from several significant problems.
Firstly, this is complex, low level, cross-platform code that integrates with the underlying operating system across a variety of POSIX platforms (including Mac OS X) and Windows. The CPython BuildBot fleet is already set up to handle continuous integration in that context, but most of the freely available continuous integration services just offer Linux, and perhaps paid access to Windows. Those services work reasonably well for software that largely runs on the abstraction layers offered by Python and other dynamic languages, as well as the more comprehensive abstraction offered by the JVM, but won't suffice for the kind of code involved here.
The OpenSSL dependency for the network security support also qualifies as
the kind of "complex binary dependency" that isn't yet handled well by the
pip
based software distribution ecosystem. Relying on a third party
binary dependency also creates potential compatibility problems for pip
when running on other interpreters like PyPy
.
Another practical problem with the idea is the fact that pip
itself
relies on the ssl
support in the standard library (with some additional
support from a bundled copy of requests
, which in turn bundles
backport.ssl_match_hostname
), and hence would require any replacement
module to also be bundled within pip
. This wouldn't pose any
insurmountable difficulties (it's just another dependency to vendor), but
it would mean yet another copy of OpenSSL to keep up to date.
This approach also has the same flaw as all other "improve security by renaming things" approaches: they completely miss the users who most need help, and raise significant barriers against being able to encourage users to do the right thing when their infrastructure supports it (since "use this other module" is a much higher impact change than "turn on this higher security setting"). Deprecating the aging SSL infrastructure in the standard library in favour of an external module would be even more user hostile than accepting the slightly increased risk of regressions associated with upgrading it in place.
Last, but certainly not least, this approach suffers from the same problem
as the idea of doing a Python 2.8 release: likely not solving the actual
problem. Commercial redistributors of Python are set up to redistribute
Python, and a pre-existing set of additional packages. Getting new
packages added to the pre-existing set can be done, but means approaching
each and every redistributor and asking them to update their
repackaging process accordingly. By contrast, the approach described in
this PEP would require redistributors to deliberately opt out of the
security enhancements (by switching to redistributing directly from the
2.7-legacy-ssl
branch rather than the main 2.7
branch), which most
of them are unlikely to do.
Open Questions
- I believe I've addressed all the technical and scope questions I had, or others raised. That just leaves the question of "If we agree to this plan, who is actually going to handle all the extra work involved?" :)
Disclosure of Interest
The author of this PEP currently works for Red Hat on test automation tools. If this proposal is accepted, I will be strongly encouraging Red Hat to take advantage of the resulting opportunity to help improve the overall security of the Python ecosystem. However, I do not speak for Red Hat in this matter, and cannot make any commitments on Red Hat's behalf.
Acknowledgements
Thanks to Christian Heimes for his recent efforts on greatly improving Python's SSL support in the Python 3 series, and a variety of members of the Python community for helping me to better understand the implications of the default settings we provide in our SSL modules, and the impact that tolerating the use of SSL infrastructure that was defined in 2010 (Python 2.7) or even 2008 (Python 2.6) potentially has for the security of the web as a whole.
Christian and Donald Stufft also provided valuable feedback on a preliminary draft of this proposal.
Thanks also to participants in the python-dev mailing list threads [1,2]_
References
.. [1] https://mail.python.org/pipermail/python-dev/2014-March/133334.html .. [2] https://mail.python.org/pipermail/python-dev/2014-March/133389.html .. [3] https://mail.python.org/pipermail/python-dev/2014-March/133438.html .. [4] https://mail.python.org/pipermail/python-dev/2014-March/133347.html
Copyright
This document has been placed in the public domain.
-- Nick Coghlan | ncoghlan at gmail.com | Brisbane, Australia
- Previous message: [Python-Dev] cpython: #20145: assert[Raises|Warns]Regex now raise TypeError on bad regex.
- Next message: [Python-Dev] PEP 466 (round 3): Python 2 network security enhancements
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]