Update PEP 493 based on python-dev discussion
This commit is contained in:
parent
dda4b60269
commit
14466c2300
233
pep-0493.txt
233
pep-0493.txt
|
@ -51,70 +51,152 @@ old behaviour. Unfortunately, the ``sitecustomize.py`` based technique proposed
|
|||
to allow system administrators to disable the feature by default in their
|
||||
Standard Operating Environment definition has been determined not to work in
|
||||
at least some cases. The specific case of interest to the authors of this PEP
|
||||
is the one where a commercial redistributor aims to provide their users with
|
||||
a smoother migration path than the standard one provided by consuming the
|
||||
upstream CPython 2.7 distribution directly [#].
|
||||
|
||||
.. [#] https://bugzilla.redhat.com/show_bug.cgi?id=1173041
|
||||
is the one where a commercial redistributor aims to provide their users with a
|
||||
`smoother migration path <https://bugzilla.redhat.com/show_bug.cgi?id=1173041>`__
|
||||
than the standard one provided by consuming the upstream CPython 2.7
|
||||
distribution directly, but other potential challenges have also been pointed
|
||||
out with updating embedded Python runtimes and other user level installations
|
||||
of Python.
|
||||
|
||||
Rather than allowing a plethora of mutually incompatibile migration techniques
|
||||
to bloom, this PEP proposes a recommended approach for redistributors to take
|
||||
when addressing this problem on behalf of their users that provides the
|
||||
following capabilities:
|
||||
to bloom, this PEP proposes two alternative approaches that redistributors
|
||||
may take when addressing these problems. Redistributors may choose to implement
|
||||
one, both, or neither of these approaches based on their assessment of the
|
||||
needs of their particular userbase.
|
||||
|
||||
* infrastructure administrators restoring the old behaviour as part of their
|
||||
standard system configuration
|
||||
* redistributors restoring the old behaviour as part of their standard
|
||||
platform configuration
|
||||
* infrastructure administators optionally and explicitly opting in to accepting
|
||||
a change in default behaviour at a future point in time as determined by their
|
||||
chosen redistributor
|
||||
These designs are being proposed as a recommendation for redistributors, rather
|
||||
than as new upstream features, as they are needed purely to support legacy
|
||||
environments migrating from older versions of Python 2.7. Neither approach
|
||||
is being proposed as an upstream Python 2.7 feature, nor as a feature in any
|
||||
version of Python 3 (whether published directly by the Python Software
|
||||
Foundation or by a redistributor).
|
||||
|
||||
It aims to do this without introducing any new attack vectors that allow
|
||||
the security configuration to be downgraded back to the older less secure
|
||||
defaults.
|
||||
Recommendation for backporting to earlier Python versions
|
||||
=========================================================
|
||||
|
||||
This design is being proposed as a recommendation for redistributors, rather
|
||||
than as a new upstream feature, as it is needed primarily to support legacy
|
||||
environments migrating from older versions of Python 2.7 (The PEP authors
|
||||
aren't *opposed* to this capability existing as an upstream feature, we just
|
||||
don't need that ourselves - our aim is to avoid different redistributors
|
||||
doing different things, not to push the change upstream).
|
||||
Some redistributors, most notably Linux distributions, may choose to backport
|
||||
the PEP 476 HTTPS verification changes to modified Python versions based on
|
||||
earlier Python 2 maintenance releases. In these cases, a configuration
|
||||
mechanism is needed that provides:
|
||||
|
||||
Recommendation
|
||||
==============
|
||||
* an opt-in model that allows the decision to enable HTTPS certificate
|
||||
verification to be made independently of the decision to upgrade to the
|
||||
Python version where the feature was first backported
|
||||
* the ability for system administrators to set the default behaviour of Python
|
||||
applications and scripts run directly in the system Python installation
|
||||
* the ability for system administrators to set the default behaviour of Python
|
||||
applications and scripts run in a ``virtualenv`` created virtual environment
|
||||
* the ability for the redistributor to consider changing the default behaviour
|
||||
of *new* installations at some point in the future without impacting existing
|
||||
installations that have been explicitly configured to skip verifying HTTPS
|
||||
certificates by default
|
||||
|
||||
To smooth the migration path to verifying HTTPS certificates by default, it is
|
||||
recommended that redistributors:
|
||||
The recommended solution for this scenario should also avoid introducing any
|
||||
new attack vectors that don't already allow direct attacks against the system
|
||||
certificate store.
|
||||
|
||||
* patch the ``ssl`` module to read a global configuration file when the module
|
||||
is imported
|
||||
* default to verifying certificates if this configuration file is not present
|
||||
* support the following three modes of operation in that configuration file:
|
||||
This approach should not be used for any Python installation that advertises
|
||||
itself as providing Python 2.7.9 or later, as most Python users will have the
|
||||
reasonable expectation that all such environments will validate HTTPS
|
||||
certificates by default.
|
||||
|
||||
Recommended modifications to the Python standard library
|
||||
--------------------------------------------------------
|
||||
|
||||
The recommended approach to backporting the PEP 476 modifications to an earlier
|
||||
point release is to implement the following changes relative to the default
|
||||
PEP 476 behaviour implemented in Python 2.7.9+:
|
||||
|
||||
* modify the ``ssl`` module to read a system wide configuration file when the
|
||||
module is first imported into a Python process
|
||||
* default to verifying HTTPS certificates if this configuration file is not
|
||||
present (this preserves the upstream default behaviour in the absence of the
|
||||
configuration file)
|
||||
* if the ``sys.real_prefix`` attribute is defined, read the configuration
|
||||
setting for virtual environments, otherwise read the configuration setting
|
||||
for the system Python
|
||||
* support selection between the following three modes of operation:
|
||||
|
||||
* ensure HTTPS certificate verification is enabled
|
||||
* ensure HTTPS certificate verification is disabled
|
||||
* delegate the decision to the redistributor modifying upstream Python
|
||||
* delegate the decision to the redistributor providing this Python version
|
||||
|
||||
An example patch is available at [#].
|
||||
|
||||
.. [#] https://bugs.python.org/issue23857
|
||||
* set the ``ssl._create_default_https_context`` function to be an alias for
|
||||
either ``ssl.create_default_context`` or ``ssl._create_unverified_context``
|
||||
based on the given configuration setting.
|
||||
|
||||
Recommended file location
|
||||
-------------------------
|
||||
|
||||
TBD separately for \*nix and Windows
|
||||
This approach is currently only defined for \*nix system Python installations.
|
||||
|
||||
The recommended configuration file name is
|
||||
(to be confirmed, currently ``/etc/python/cert-verification.cfg``).
|
||||
|
||||
The ``.cfg`` filename extension is recommended for consistency with the
|
||||
``pyvenv.cfg`` used by the ``venv`` module in Python 3's standard library.
|
||||
|
||||
Recommended file format
|
||||
-----------------------
|
||||
|
||||
ConfigParser ini-style format, other details TBD
|
||||
The configuration file should use a ConfigParser ini-style format with a
|
||||
single section named ``[https]`` containing one required setting ``verify``,
|
||||
and one optional setting ``verify_in_virtualenv``.
|
||||
|
||||
Permitted values for ``verify`` and ``verify_in_virtualenv`` are:
|
||||
|
||||
* ``enable``: ensure HTTPS certificate verification is enabled by default
|
||||
* ``disable``: ensure HTTPS certificate verification is disabled by default
|
||||
* ``platform_default``: delegate the decision to the redistributor providing
|
||||
this particular Python version
|
||||
|
||||
If the ``[https]`` section or the ``verify`` setting are missing, or if the
|
||||
``verify`` setting is set to an unknown value, it should be treated as if the
|
||||
configuration file is not present.
|
||||
|
||||
If ``sys.real_prefix`` is set, and the ``verify_in_virtualenv`` setting is
|
||||
present and set to one of the known options, then it should be used in
|
||||
preference to the ``verify`` setting.
|
||||
|
||||
Example implementation
|
||||
----------------------
|
||||
|
||||
::
|
||||
|
||||
def _get_https_context_factory():
|
||||
config_file = '/etc/python/cert-verification.conf'
|
||||
context_factories = {
|
||||
'enable': create_default_context,
|
||||
'disable': _create_unverified_context,
|
||||
'platform_default': _create_unverified_context, # For now :)
|
||||
}
|
||||
# Check for a system-wide override of the default behaviour
|
||||
import configparser
|
||||
config = configparser.RawConfigParser()
|
||||
config.read(config_file)
|
||||
section = 'https'
|
||||
try:
|
||||
verify_mode = config.get('https', 'verify')
|
||||
except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
|
||||
verify_mode = 'enable'
|
||||
else:
|
||||
# Check if there's a different default for a virtual environment
|
||||
if hasattr(sys, "real_prefix"):
|
||||
try:
|
||||
verify_mode = config.get('https', 'verify_in_virtualenv')
|
||||
except (ConfigParser.NoOptionError):
|
||||
pass
|
||||
return context_factories.get(verify_mode, create_default_context)
|
||||
|
||||
_create_default_https_context = _get_https_context_factory()
|
||||
|
||||
|
||||
Security Considerations
|
||||
=======================
|
||||
-----------------------
|
||||
|
||||
The specific recommendations here are designed to work for privileged, security
|
||||
sensitive processes, being run in the following locked down configuration:
|
||||
The specific recommendations for the backporting case are designed to work for
|
||||
privileged, security sensitive processes, even those being run in the following
|
||||
locked down configuration:
|
||||
|
||||
* run from a locked down administrator controlled directory rather than a normal
|
||||
user directory (preventing ``sys.path[0]`` based privilege escalation attacks)
|
||||
|
@ -126,7 +208,7 @@ sensitive processes, being run in the following locked down configuration:
|
|||
escalation attacks)
|
||||
|
||||
The intent is that the *only* reason HTTPS verification should be getting
|
||||
turned off globally is because:
|
||||
turned off system wide when using this approach is because:
|
||||
|
||||
* an end user is running a redistributor supported version of CPython rather
|
||||
than running upstream CPython directly
|
||||
|
@ -143,6 +225,73 @@ ensures that in any situation where an attacker gains sufficient access to allow
|
|||
them to modify the configuration file, they're likely already in a position to
|
||||
attack the system certificate store directly.
|
||||
|
||||
Recommendation for an environment variable based security downgrade
|
||||
===================================================================
|
||||
|
||||
Some redistributors may wish to provide a per-application option to disable
|
||||
certificate verification in selected applications that run on or embed CPython
|
||||
without needing to modify the application itself.
|
||||
|
||||
In these cases, a configuration mechanism is needed that provides:
|
||||
|
||||
* an opt-out model that allows certificate verification to be selectively
|
||||
turned off for particular applications after upgrading to a version of
|
||||
Python that verifies certificates by default
|
||||
* the ability for all users to configure this setting on a per-application
|
||||
basis, rather than on a per-system, or per-Python-installation basis
|
||||
|
||||
This recommendation is not considered appropriate for system wide Python
|
||||
installations, but may be suitable for user level Python installations and
|
||||
versions of Python embedded in or bundled with particular applications.
|
||||
|
||||
This approach may be used for Python installations that advertises
|
||||
themselves as providing Python 2.7.9 or later.
|
||||
|
||||
Recommended modifications to the Python standard library
|
||||
--------------------------------------------------------
|
||||
|
||||
The recommended approach to providing a per-application configuration setting
|
||||
for HTTPS certificate verification that doesn't require modifications to the
|
||||
application itself is to:
|
||||
|
||||
* modify the ``ssl`` module to read the ``PYTHONHTTPSVERIFY`` environment
|
||||
variable when the module is first imported into a Python process
|
||||
* set the ``ssl._create_default_https_context`` function to be an alias for
|
||||
``ssl._create_unverified_context`` if this environment variable is present
|
||||
and set to '0'
|
||||
* otherwise, set the ``ssl._create_default_https_context`` function to be an
|
||||
alias for ``ssl.create_default_context`` as usual
|
||||
|
||||
Example implementation
|
||||
----------------------
|
||||
|
||||
::
|
||||
|
||||
def _get_https_context_factory():
|
||||
config_setting = os.environ.get('PYTHONHTTPSVERIFY')
|
||||
if config_setting == '0':
|
||||
return _create_unverified_context
|
||||
return create_default_context
|
||||
|
||||
_create_default_https_context = _get_https_context_factory()
|
||||
|
||||
|
||||
Security Considerations
|
||||
-----------------------
|
||||
|
||||
Relative to an unmodified version of CPython 2.7.9 or later, this approach
|
||||
does introduce a new downgrade attack against the default security settings
|
||||
that potentially allows a sufficiently determined attacker to revert Python
|
||||
to the vulnerable configuration used in CPython 2.7.8 and earlier releases.
|
||||
Such an attack requires the ability to modify the execution environment of
|
||||
a Python process prior to the import of the ``ssl`` module.
|
||||
|
||||
Redistributors should balance this marginal increase in risk against the
|
||||
ability to offer a smoother migration path to their users when deciding whether
|
||||
or not it is appropriate for them to implement this per-application "opt out"
|
||||
model.
|
||||
|
||||
|
||||
Copyright
|
||||
=========
|
||||
|
||||
|
|
Loading…
Reference in New Issue