PEP 493: simplify detection of the capability
This commit is contained in:
parent
f0951bcf36
commit
baef915b05
75
pep-0493.txt
75
pep-0493.txt
|
@ -72,6 +72,25 @@ version of Python 3 (whether published directly by the Python Software
|
|||
Foundation or by a redistributor).
|
||||
|
||||
|
||||
Requirements for capability detection
|
||||
=====================================
|
||||
|
||||
As these recommendations are intended to cover backports to earlier Python
|
||||
versions, the Python version number cannot be used as a reliable means for
|
||||
detecting them. Instead, the recommendations are defined to allow the presence
|
||||
or absence of the feature to be determined using the following technique::
|
||||
|
||||
python -c "import ssl; ssl._relevant_attribute"
|
||||
|
||||
This will fail with `AttributeError` (and hence a non-zero return code) if the
|
||||
relevant capability is not available.
|
||||
|
||||
The marker attributes are prefixed with an underscore to indicate the
|
||||
implementation dependent nature of these capabilities - not all Python
|
||||
distributions will offer them, only those that are providing a multi-stage
|
||||
migration process from the legacy HTTPS handling to the new default behaviour.
|
||||
|
||||
|
||||
Recommendation for an environment variable based security downgrade
|
||||
===================================================================
|
||||
|
||||
|
@ -91,6 +110,19 @@ This approach may be used for any redistributor provided version of Python 2.7,
|
|||
including those that advertise themselves as providing Python 2.7.9 or later.
|
||||
|
||||
|
||||
Required marker attribute
|
||||
-------------------------
|
||||
|
||||
The required marker attribute on the ``ssl`` module when implementing this
|
||||
recommendation is::
|
||||
|
||||
_https_verify_envvar = 'PYTHONHTTPSVERIFY'
|
||||
|
||||
This not only makes it straightforward to detect the presence (or absence) of
|
||||
the capability, it also makes it possible to programmatically determine the
|
||||
relevant environment variable name.
|
||||
|
||||
|
||||
Recommended modifications to the Python standard library
|
||||
--------------------------------------------------------
|
||||
|
||||
|
@ -112,8 +144,10 @@ Example implementation
|
|||
|
||||
::
|
||||
|
||||
_https_verify_envvar = 'PYTHONHTTPSVERIFY'
|
||||
|
||||
def _get_https_context_factory():
|
||||
config_setting = os.environ.get('PYTHONHTTPSVERIFY')
|
||||
config_setting = os.environ.get(_https_verify_envvar)
|
||||
if config_setting == '0':
|
||||
return _create_unverified_context
|
||||
return create_default_context
|
||||
|
@ -128,13 +162,10 @@ 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.
|
||||
However, such an attack requires the ability to modify the execution
|
||||
environment of a Python process prior to the import of the ``ssl`` module,
|
||||
and any attacker with such access would already be able to modify the
|
||||
behaviour of the underlying OpenSSL implementation.
|
||||
|
||||
|
||||
Recommendation for backporting to earlier Python versions
|
||||
|
@ -161,6 +192,19 @@ reasonable expectation that all such environments will validate HTTPS
|
|||
certificates by default.
|
||||
|
||||
|
||||
Required marker attribute
|
||||
-------------------------
|
||||
|
||||
The required marker attribute on the ``ssl`` module when implementing this
|
||||
recommendation is::
|
||||
|
||||
_cert_verification_config = '<path to configuration file>'
|
||||
|
||||
This not only makes it straightforward to detect the presence (or absence) of
|
||||
the capability, it also makes it possible to programmatically determine the
|
||||
relevant configuration file name.
|
||||
|
||||
|
||||
Recommended modifications to the Python standard library
|
||||
--------------------------------------------------------
|
||||
|
||||
|
@ -218,9 +262,10 @@ Example implementation
|
|||
|
||||
::
|
||||
|
||||
_cert_verification_config = '/etc/python/cert-verification.cfg'
|
||||
|
||||
def _get_https_context_factory():
|
||||
# Check for a system-wide override of the default behaviour
|
||||
config_file = '/etc/python/cert-verification.cfg'
|
||||
context_factories = {
|
||||
'enable': create_default_context,
|
||||
'disable': _create_unverified_context,
|
||||
|
@ -228,7 +273,7 @@ Example implementation
|
|||
}
|
||||
import ConfigParser
|
||||
config = ConfigParser.RawConfigParser()
|
||||
config.read(config_file)
|
||||
config.read(_cert_verification_config)
|
||||
try:
|
||||
verify_mode = config.get('https', 'verify')
|
||||
except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
|
||||
|
@ -268,7 +313,7 @@ turned off system wide when using this approach is because:
|
|||
(at least for the time being)
|
||||
|
||||
Using an administrator controlled configuration file rather than an environment
|
||||
variable has the essential feature of providing a smoother migraiton path, even
|
||||
variable has the essential feature of providing a smoother migration path, even
|
||||
for applications being run with the ``-E`` switch.
|
||||
|
||||
|
||||
|
@ -289,16 +334,18 @@ Example implementation
|
|||
|
||||
::
|
||||
|
||||
_https_verify_envvar = 'PYTHONHTTPSVERIFY'
|
||||
_cert_verification_config = '/etc/python/cert-verification.cfg'
|
||||
|
||||
def _get_https_context_factory():
|
||||
# Check for am environmental override of the default behaviour
|
||||
config_setting = os.environ.get('PYTHONHTTPSVERIFY')
|
||||
config_setting = os.environ.get(_https_verify_envvar)
|
||||
if config_setting is not None:
|
||||
if config_setting == '0':
|
||||
return _create_unverified_context
|
||||
return create_default_context
|
||||
|
||||
# Check for a system-wide override of the default behaviour
|
||||
config_file = '/etc/python/cert-verification.cfg'
|
||||
context_factories = {
|
||||
'enable': create_default_context,
|
||||
'disable': _create_unverified_context,
|
||||
|
@ -306,7 +353,7 @@ Example implementation
|
|||
}
|
||||
import ConfigParser
|
||||
config = ConfigParser.RawConfigParser()
|
||||
config.read(config_file)
|
||||
config.read(_cert_verification_config)
|
||||
try:
|
||||
verify_mode = config.get('https', 'verify')
|
||||
except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
|
||||
|
|
Loading…
Reference in New Issue