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).
|
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
|
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.
|
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
|
Recommended modifications to the Python standard library
|
||||||
--------------------------------------------------------
|
--------------------------------------------------------
|
||||||
|
|
||||||
|
@ -112,8 +144,10 @@ Example implementation
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
|
_https_verify_envvar = 'PYTHONHTTPSVERIFY'
|
||||||
|
|
||||||
def _get_https_context_factory():
|
def _get_https_context_factory():
|
||||||
config_setting = os.environ.get('PYTHONHTTPSVERIFY')
|
config_setting = os.environ.get(_https_verify_envvar)
|
||||||
if config_setting == '0':
|
if config_setting == '0':
|
||||||
return _create_unverified_context
|
return _create_unverified_context
|
||||||
return create_default_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
|
does introduce a new downgrade attack against the default security settings
|
||||||
that potentially allows a sufficiently determined attacker to revert Python
|
that potentially allows a sufficiently determined attacker to revert Python
|
||||||
to the vulnerable configuration used in CPython 2.7.8 and earlier releases.
|
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
|
However, such an attack requires the ability to modify the execution
|
||||||
a Python process prior to the import of the ``ssl`` module.
|
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
|
||||||
Redistributors should balance this marginal increase in risk against the
|
behaviour of the underlying OpenSSL implementation.
|
||||||
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.
|
|
||||||
|
|
||||||
|
|
||||||
Recommendation for backporting to earlier Python versions
|
Recommendation for backporting to earlier Python versions
|
||||||
|
@ -161,6 +192,19 @@ reasonable expectation that all such environments will validate HTTPS
|
||||||
certificates by default.
|
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
|
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():
|
def _get_https_context_factory():
|
||||||
# Check for a system-wide override of the default behaviour
|
# Check for a system-wide override of the default behaviour
|
||||||
config_file = '/etc/python/cert-verification.cfg'
|
|
||||||
context_factories = {
|
context_factories = {
|
||||||
'enable': create_default_context,
|
'enable': create_default_context,
|
||||||
'disable': _create_unverified_context,
|
'disable': _create_unverified_context,
|
||||||
|
@ -228,7 +273,7 @@ Example implementation
|
||||||
}
|
}
|
||||||
import ConfigParser
|
import ConfigParser
|
||||||
config = ConfigParser.RawConfigParser()
|
config = ConfigParser.RawConfigParser()
|
||||||
config.read(config_file)
|
config.read(_cert_verification_config)
|
||||||
try:
|
try:
|
||||||
verify_mode = config.get('https', 'verify')
|
verify_mode = config.get('https', 'verify')
|
||||||
except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
|
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)
|
(at least for the time being)
|
||||||
|
|
||||||
Using an administrator controlled configuration file rather than an environment
|
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.
|
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():
|
def _get_https_context_factory():
|
||||||
# Check for am environmental override of the default behaviour
|
# 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 is not None:
|
||||||
if config_setting == '0':
|
if config_setting == '0':
|
||||||
return _create_unverified_context
|
return _create_unverified_context
|
||||||
return create_default_context
|
return create_default_context
|
||||||
|
|
||||||
# Check for a system-wide override of the default behaviour
|
# Check for a system-wide override of the default behaviour
|
||||||
config_file = '/etc/python/cert-verification.cfg'
|
|
||||||
context_factories = {
|
context_factories = {
|
||||||
'enable': create_default_context,
|
'enable': create_default_context,
|
||||||
'disable': _create_unverified_context,
|
'disable': _create_unverified_context,
|
||||||
|
@ -306,7 +353,7 @@ Example implementation
|
||||||
}
|
}
|
||||||
import ConfigParser
|
import ConfigParser
|
||||||
config = ConfigParser.RawConfigParser()
|
config = ConfigParser.RawConfigParser()
|
||||||
config.read(config_file)
|
config.read(_cert_verification_config)
|
||||||
try:
|
try:
|
||||||
verify_mode = config.get('https', 'verify')
|
verify_mode = config.get('https', 'verify')
|
||||||
except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
|
except (ConfigParser.NoSectionError, ConfigParser.NoOptionError):
|
||||||
|
|
Loading…
Reference in New Issue