2015-09-19 18:58:49 -04:00
|
|
|
|
PEP: 506
|
|
|
|
|
Title: Adding A Secrets Module To The Standard Library
|
|
|
|
|
Version: $Revision$
|
|
|
|
|
Last-Modified: $Date$
|
|
|
|
|
Author: Steven D'Aprano <steve@pearwood.info>
|
|
|
|
|
Status: Draft
|
|
|
|
|
Type: Standards Track
|
|
|
|
|
Content-Type: text/x-rst
|
|
|
|
|
Created: 19-Sep-2015
|
|
|
|
|
Python-Version: 3.6
|
|
|
|
|
Post-History:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Abstract
|
|
|
|
|
========
|
|
|
|
|
|
|
|
|
|
This PEP proposes the addition of a module for common security-related
|
|
|
|
|
functions such as generating tokens to the Python standard library.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Definitions
|
|
|
|
|
===========
|
|
|
|
|
|
|
|
|
|
Some common abbreviations used in this proposal:
|
|
|
|
|
|
|
|
|
|
* PRNG:
|
|
|
|
|
|
|
|
|
|
Pseudo Random Number Generator. A deterministic algorithm used
|
|
|
|
|
to produce random-looking numbers with certain desirable
|
|
|
|
|
statistical properties.
|
|
|
|
|
|
|
|
|
|
* CSPRNG:
|
|
|
|
|
|
|
|
|
|
Cryptographically Strong Pseudo Random Number Generator. An
|
|
|
|
|
algorithm used to produce random-looking numbers which are
|
|
|
|
|
resistant to prediction.
|
|
|
|
|
|
|
|
|
|
* MT:
|
|
|
|
|
|
|
|
|
|
Mersenne Twister. An extensively studied PRNG which is currently
|
|
|
|
|
used by the ``random`` module as the default.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Rationale
|
|
|
|
|
=========
|
|
|
|
|
|
|
|
|
|
This proposal is motivated by concerns that Python's standard library
|
|
|
|
|
makes it too easy for developers to inadvertently make serious security
|
|
|
|
|
errors. Theo de Raadt, the founder of OpenBSD, contacted Guido van Rossum
|
2015-09-19 20:21:55 -04:00
|
|
|
|
and expressed some concern [1]_ about the use of MT for generating sensitive
|
2015-09-19 18:58:49 -04:00
|
|
|
|
information such as passwords, secure tokens, session keys and similar.
|
|
|
|
|
|
|
|
|
|
Although the documentation for the random module explicitly states that
|
2015-09-19 20:21:55 -04:00
|
|
|
|
the default is not suitable for security purposes [2]_, it is strongly
|
2015-09-19 18:58:49 -04:00
|
|
|
|
believed that this warning may be missed, ignored or misunderstood by
|
|
|
|
|
many Python developers. In particular:
|
|
|
|
|
|
|
|
|
|
* developers may not have read the documentation and consequently
|
|
|
|
|
not seen the warning;
|
|
|
|
|
|
|
|
|
|
* they may not realise that their specific use of it has security
|
|
|
|
|
implications; or
|
|
|
|
|
|
|
|
|
|
* not realising that there could be a problem, they have copied code
|
|
|
|
|
(or learned techniques) from websites which don't offer best
|
|
|
|
|
practises.
|
|
|
|
|
|
2015-09-19 20:21:55 -04:00
|
|
|
|
The first [3]_ hit when searching for "python how to generate passwords" on
|
2015-09-19 18:58:49 -04:00
|
|
|
|
Google is a tutorial that uses the default functions from the ``random``
|
2015-09-19 20:21:55 -04:00
|
|
|
|
module [4]_. Although it is not intended for use in web applications, it is
|
2015-09-19 18:58:49 -04:00
|
|
|
|
likely that similar techniques find themselves used in that situation.
|
|
|
|
|
The second hit is to a StackOverflow question about generating
|
2015-09-19 20:21:55 -04:00
|
|
|
|
passwords [5]_. Most of the answers given, including the accepted one, use
|
2015-09-19 18:58:49 -04:00
|
|
|
|
the default functions. When one user warned that the default could be
|
2015-09-19 20:21:55 -04:00
|
|
|
|
easily compromised, they were told "I think you worry too much." [6]_
|
2015-09-19 18:58:49 -04:00
|
|
|
|
|
|
|
|
|
This strongly suggests that the existing ``random`` module is an attractive
|
|
|
|
|
nuisance when it comes to generating (for example) passwords or secure
|
|
|
|
|
tokens.
|
|
|
|
|
|
|
|
|
|
Additional motivation (of a more philosophical bent) can be found in the
|
2015-09-19 20:21:55 -04:00
|
|
|
|
post which first proposed this idea [7]_.
|
2015-09-19 18:58:49 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Proposal
|
|
|
|
|
========
|
|
|
|
|
|
|
|
|
|
Alternative proposals have focused on the default PRNG in the ``random``
|
|
|
|
|
module, with the aim of providing "secure by default" cryptographically
|
|
|
|
|
strong primitives that developers can build upon without thinking about
|
|
|
|
|
security. (See Alternatives below.) This proposes a different approach:
|
|
|
|
|
|
|
|
|
|
* The standard library already provides cryptographically strong
|
|
|
|
|
primitives, but many users don't know they exist or when to use them.
|
|
|
|
|
|
|
|
|
|
* Instead of requiring crypto-naive users to write secure code, the
|
|
|
|
|
standard library should include a set of ready-to-use "batteries" for
|
|
|
|
|
the most common needs, such as generating secure tokens. This code
|
|
|
|
|
will both directly satisfy a need ("How do I generate a password reset
|
|
|
|
|
token?"), and act as an example of acceptable practises which
|
2015-09-19 20:21:55 -04:00
|
|
|
|
developers can learn from [8]_.
|
2015-09-19 18:58:49 -04:00
|
|
|
|
|
|
|
|
|
To do this, this PEP proposes that we add a new module to the standard
|
|
|
|
|
library, with the suggested name ``secrets``. This module will contain a
|
|
|
|
|
set of ready-to-use functions for common activities with security
|
|
|
|
|
implications, together with some lower-level primitives.
|
|
|
|
|
|
|
|
|
|
The suggestion is that ``secrets`` becomes the go-to module for dealing
|
|
|
|
|
with anything which should remain secret (passwords, tokens, etc.)
|
|
|
|
|
while the ``random`` module remains backward-compatible.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
API and Implementation
|
|
|
|
|
======================
|
|
|
|
|
|
|
|
|
|
The contents of the ``secrets`` module is expected to evolve over time, and
|
|
|
|
|
likely will evolve between the time of writing this PEP and actual release
|
2015-09-19 20:21:55 -04:00
|
|
|
|
in the standard library [9]_. At the time of writing, the following functions
|
2015-09-19 18:58:49 -04:00
|
|
|
|
have been suggested:
|
|
|
|
|
|
|
|
|
|
* A high-level function for generating secure tokens suitable for use
|
|
|
|
|
in (e.g.) password recovery, as session keys, etc.
|
|
|
|
|
|
|
|
|
|
* A limited interface to the system CSPRNG, using either ``os.urandom``
|
|
|
|
|
directly or ``random.SystemRandom``. Unlike the ``random`` module, this
|
|
|
|
|
does not need to provide methods for seeding, getting or setting the
|
|
|
|
|
state, or any non-uniform distributions. It should provide the
|
|
|
|
|
following:
|
|
|
|
|
|
|
|
|
|
- A function for choosing items from a sequence, ``secrets.choice``.
|
|
|
|
|
- A function for generating an integer within some range, such as
|
|
|
|
|
``secrets.randrange`` or ``secrets.randint``.
|
|
|
|
|
- A function for generating a given number of random bits and/or bytes
|
|
|
|
|
as an integer.
|
|
|
|
|
- A similar function which returns the value as a hex digit string.
|
|
|
|
|
|
|
|
|
|
* ``hmac.compare_digest`` under the name ``equal``.
|
|
|
|
|
|
|
|
|
|
The consensus appears to be that there is no need to add a new CSPRNG to
|
|
|
|
|
the ``random`` module to support these uses, ``SystemRandom`` will be
|
|
|
|
|
sufficient.
|
|
|
|
|
|
2015-09-19 20:21:55 -04:00
|
|
|
|
Some illustrative implementations have been given by Nick Coghlan [10]_.
|
2015-09-19 18:58:49 -04:00
|
|
|
|
This idea has also been discussed on the issue tracker for the
|
2015-09-19 20:21:55 -04:00
|
|
|
|
"cryptography" module [11]_.
|
2015-09-19 18:58:49 -04:00
|
|
|
|
|
|
|
|
|
The ``secrets`` module itself will be pure Python, and other Python
|
|
|
|
|
implementations can easily make use of it unchanged, or adapt it as
|
|
|
|
|
necessary.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Alternatives
|
|
|
|
|
============
|
|
|
|
|
|
|
|
|
|
One alternative is to change the default PRNG provided by the ``random``
|
2015-09-19 20:21:55 -04:00
|
|
|
|
module [12]_. This received considerable scepticism and outright opposition:
|
2015-09-19 18:58:49 -04:00
|
|
|
|
|
|
|
|
|
* There is fear that a CSPRNG may be slower than the current PRNG (which
|
|
|
|
|
in the case of MT is already quite slow).
|
|
|
|
|
|
|
|
|
|
* Some applications (such as scientific simulations, and replaying
|
|
|
|
|
gameplay) require the ability to seed the PRNG into a known state,
|
|
|
|
|
which a CSPRNG lacks by design.
|
|
|
|
|
|
|
|
|
|
* Another major use of the ``random`` module is for simple "guess a number"
|
|
|
|
|
games written by beginners, and many people are loath to make any
|
|
|
|
|
change to the ``random`` module which may make that harder.
|
|
|
|
|
|
|
|
|
|
* Although there is no proposal to remove MT from the ``random`` module,
|
|
|
|
|
there was considerable hostility to the idea of having to opt-in to
|
|
|
|
|
a non-CSPRNG or any backwards-incompatible changes.
|
|
|
|
|
|
|
|
|
|
* Demonstrated attacks against MT are typically against PHP applications.
|
|
|
|
|
It is believed that PHP's version of MT is a significantly softer target
|
2015-09-19 20:21:55 -04:00
|
|
|
|
than Python's version, due to a poor seeding technique [13]_. Consequently,
|
2015-09-19 18:58:49 -04:00
|
|
|
|
without a proven attack against Python applications, many people object
|
|
|
|
|
to a backwards-incompatible change.
|
|
|
|
|
|
|
|
|
|
Nick Coghlan made an earlier suggestion for a globally configurable PRNG
|
2015-09-19 20:21:55 -04:00
|
|
|
|
which uses the system CSPRNG by default [14]_, but has since hinted that he
|
|
|
|
|
may withdraw it in favour of this proposal [15]_.
|
2015-09-19 18:58:49 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Comparison To Other Languages
|
|
|
|
|
=============================
|
|
|
|
|
|
|
|
|
|
* PHP
|
|
|
|
|
|
2015-09-19 20:21:55 -04:00
|
|
|
|
PHP includes a function ``uniqid`` [16]_ which by default returns a
|
2015-09-19 18:58:49 -04:00
|
|
|
|
thirteen character string based on the current time in microseconds.
|
|
|
|
|
Translated into Python syntax, it has the following signature::
|
|
|
|
|
|
|
|
|
|
def uniqid(prefix='', more_entropy=False)->str
|
|
|
|
|
|
|
|
|
|
The PHP documentation warns that this function is not suitable for
|
|
|
|
|
security purposes. Nevertheless, various mature, well-known PHP
|
|
|
|
|
applications use it for that purpose (citation needed).
|
|
|
|
|
|
2015-09-19 20:21:55 -04:00
|
|
|
|
PHP 5.3 and better also includes a function ``openssl_random_pseudo_bytes``
|
|
|
|
|
[17]_. Translated into Python syntax, it has roughly the following
|
|
|
|
|
signature::
|
2015-09-19 18:58:49 -04:00
|
|
|
|
|
|
|
|
|
def openssl_random_pseudo_bytes(length:int)->Tuple[str, bool]
|
|
|
|
|
|
|
|
|
|
This function returns a pseudo-random string of bytes of the given
|
|
|
|
|
length, and an boolean flag giving whether the string is considered
|
|
|
|
|
cryptographically strong. The PHP manual suggests that returning
|
|
|
|
|
anything but True should be rare except for old or broken platforms.
|
|
|
|
|
|
|
|
|
|
* Javascript
|
|
|
|
|
|
2015-09-19 20:21:55 -04:00
|
|
|
|
Based on a rather cursory search [18]_, there doesn't appear to be any
|
2015-09-19 18:58:49 -04:00
|
|
|
|
well-known standard functions for producing strong random values in
|
|
|
|
|
Javascript, although there may be good quality third-party libraries.
|
|
|
|
|
Standard Javascript doesn't seem to include an interface to the
|
|
|
|
|
system CSPRNG either, and people have extensively written about the
|
2015-09-19 20:21:55 -04:00
|
|
|
|
weaknesses of Javascript's ``Math.random`` [19]_.
|
2015-09-19 18:58:49 -04:00
|
|
|
|
|
|
|
|
|
* Ruby
|
|
|
|
|
|
2015-09-19 20:21:55 -04:00
|
|
|
|
The Ruby standard library includes a module ``SecureRandom`` [20]_
|
2015-09-19 18:58:49 -04:00
|
|
|
|
which includes the following methods:
|
|
|
|
|
|
|
|
|
|
* base64 - returns a Base64 encoded random string.
|
|
|
|
|
|
|
|
|
|
* hex - returns a random hexadecimal string.
|
|
|
|
|
|
|
|
|
|
* random_bytes - returns a random byte string.
|
|
|
|
|
|
|
|
|
|
* random_number - depending on the argument, returns either a random
|
|
|
|
|
integer in the range(0, n), or a random float between 0.0 and 1.0.
|
|
|
|
|
|
|
|
|
|
* urlsafe_base64 - returns a random URL-safe Base64 encoded string.
|
|
|
|
|
|
|
|
|
|
* uuid - return a version 4 random Universally Unique IDentifier.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
What Should Be The Name Of The Module?
|
|
|
|
|
======================================
|
|
|
|
|
|
|
|
|
|
There was a proposal to add a "random.safe" submodule, quoting the Zen
|
|
|
|
|
of Python "Namespaces are one honking great idea" koan. However, the
|
2015-09-19 20:21:55 -04:00
|
|
|
|
author of the Zen, Tim Peters, has come out against this idea [21]_, and
|
2015-09-19 18:58:49 -04:00
|
|
|
|
recommends a top-level module.
|
|
|
|
|
|
|
|
|
|
In discussion on the python-ideas mailing list so far, the name "secrets"
|
|
|
|
|
has received some approval, and no strong opposition.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Frequently Asked Questions
|
|
|
|
|
==========================
|
|
|
|
|
|
2015-09-19 20:21:55 -04:00
|
|
|
|
* Q: Is this a real problem? Surely MT is random enough that nobody can
|
|
|
|
|
predict its output.
|
2015-09-19 18:58:49 -04:00
|
|
|
|
|
2015-09-19 20:21:55 -04:00
|
|
|
|
A: The consensus among security professionals is that MT is not safe
|
|
|
|
|
in security contexts. It is not difficult to reconstruct the internal
|
|
|
|
|
state of MT [22]_ [23]_ and so predict all past and future values. There
|
|
|
|
|
are a number of known, practical attacks on systems using MT for
|
|
|
|
|
randomness [24]_.
|
2015-09-19 18:58:49 -04:00
|
|
|
|
|
2015-09-19 20:21:55 -04:00
|
|
|
|
While there are currently no known direct attacks on applications
|
|
|
|
|
written in Python due to the use of MT, there is widespread agreement
|
|
|
|
|
that such usage is unsafe.
|
2015-09-19 18:58:49 -04:00
|
|
|
|
|
2015-09-19 20:21:55 -04:00
|
|
|
|
* Q: Is this an alternative to specialise cryptographic software such as SSL?
|
2015-09-19 18:58:49 -04:00
|
|
|
|
|
2015-09-19 20:21:55 -04:00
|
|
|
|
A: No. This is a "batteries included" solution, not a full-featured
|
|
|
|
|
"nuclear reactor". It is intended to mitigate against some basic
|
|
|
|
|
security errors, not be a solution to all security-related issues. To
|
|
|
|
|
quote Nick Coghlan referring to his earlier proposal [25]_::
|
2015-09-19 18:58:49 -04:00
|
|
|
|
|
2015-09-19 20:21:55 -04:00
|
|
|
|
"...folks really are better off learning to use things like
|
|
|
|
|
cryptography.io for security sensitive software, so this change
|
|
|
|
|
is just about harm mitigation given that it's inevitable that a
|
|
|
|
|
non-trivial proportion of the millions of current and future
|
|
|
|
|
Python developers won't do that."
|
2015-09-19 18:58:49 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
References
|
|
|
|
|
==========
|
|
|
|
|
|
2015-09-19 20:21:55 -04:00
|
|
|
|
.. [1] https://mail.python.org/pipermail/python-ideas/2015-September/035820.html
|
2015-09-19 18:58:49 -04:00
|
|
|
|
|
2015-09-19 20:21:55 -04:00
|
|
|
|
.. [2] https://docs.python.org/3/library/random.html
|
2015-09-19 18:58:49 -04:00
|
|
|
|
|
2015-09-19 20:21:55 -04:00
|
|
|
|
.. [3] As of the date of writing. Also, as Google search terms may be
|
|
|
|
|
automatically customised for the user without their knowledge, some
|
|
|
|
|
readers may see different results.
|
2015-09-19 18:58:49 -04:00
|
|
|
|
|
2015-09-19 20:21:55 -04:00
|
|
|
|
.. [4] http://interactivepython.org/runestone/static/everyday/2013/01/3_password.html
|
2015-09-19 18:58:49 -04:00
|
|
|
|
|
2015-09-19 20:21:55 -04:00
|
|
|
|
.. [5] http://stackoverflow.com/questions/3854692/generate-password-in-python
|
2015-09-19 18:58:49 -04:00
|
|
|
|
|
2015-09-19 20:21:55 -04:00
|
|
|
|
.. [6] http://stackoverflow.com/questions/3854692/generate-password-in-python/3854766#3854766
|
2015-09-19 18:58:49 -04:00
|
|
|
|
|
2015-09-19 20:21:55 -04:00
|
|
|
|
.. [7] https://mail.python.org/pipermail/python-ideas/2015-September/036238.html
|
2015-09-19 18:58:49 -04:00
|
|
|
|
|
2015-09-19 20:21:55 -04:00
|
|
|
|
.. [8] At least those who are motivated to read the source code and documentation.
|
2015-09-19 18:58:49 -04:00
|
|
|
|
|
2015-09-19 20:21:55 -04:00
|
|
|
|
.. [9] Tim Peters suggests that bike-shedding the contents of the module will
|
|
|
|
|
be 10000 times more time consuming than actually implementing the
|
|
|
|
|
module. Words do not begin to express how much I am looking forward to
|
|
|
|
|
this.
|
2015-09-19 18:58:49 -04:00
|
|
|
|
|
2015-09-19 20:21:55 -04:00
|
|
|
|
.. [10] https://mail.python.org/pipermail/python-ideas/2015-September/036271.html
|
2015-09-19 18:58:49 -04:00
|
|
|
|
|
2015-09-19 20:21:55 -04:00
|
|
|
|
.. [11] https://github.com/pyca/cryptography/issues/2347
|
2015-09-19 18:58:49 -04:00
|
|
|
|
|
2015-09-19 20:21:55 -04:00
|
|
|
|
.. [12] Link needed.
|
2015-09-19 18:58:49 -04:00
|
|
|
|
|
2015-09-19 20:21:55 -04:00
|
|
|
|
.. [13] By default PHP seeds the MT PRNG with the time (citation needed),
|
|
|
|
|
which is exploitable by attackers, while Python seeds the PRNG with
|
|
|
|
|
output from the system CSPRNG, which is believed to be much harder to
|
|
|
|
|
exploit.
|
2015-09-19 18:58:49 -04:00
|
|
|
|
|
2015-09-19 20:21:55 -04:00
|
|
|
|
.. [14] http://legacy.python.org/dev/peps/pep-0504/
|
2015-09-19 18:58:49 -04:00
|
|
|
|
|
2015-09-19 20:21:55 -04:00
|
|
|
|
.. [15] https://mail.python.org/pipermail/python-ideas/2015-September/036243.html
|
2015-09-19 18:58:49 -04:00
|
|
|
|
|
2015-09-19 20:21:55 -04:00
|
|
|
|
.. [16] http://php.net/manual/en/function.uniqid.php
|
2015-09-19 18:58:49 -04:00
|
|
|
|
|
2015-09-19 20:21:55 -04:00
|
|
|
|
.. [17] http://php.net/manual/en/function.openssl-random-pseudo-bytes.php
|
2015-09-19 18:58:49 -04:00
|
|
|
|
|
2015-09-19 20:21:55 -04:00
|
|
|
|
.. [18] Volunteers and patches are welcome.
|
2015-09-19 18:58:49 -04:00
|
|
|
|
|
2015-09-19 20:21:55 -04:00
|
|
|
|
.. [19] http://ifsec.blogspot.fr/2012/05/cross-domain-mathrandom-prediction.html
|
2015-09-19 18:58:49 -04:00
|
|
|
|
|
2015-09-19 20:21:55 -04:00
|
|
|
|
.. [20] http://ruby-doc.org/stdlib-2.1.2/libdoc/securerandom/rdoc/SecureRandom.html
|
2015-09-19 18:58:49 -04:00
|
|
|
|
|
2015-09-19 20:21:55 -04:00
|
|
|
|
.. [21] https://mail.python.org/pipermail/python-ideas/2015-September/036254.html
|
2015-09-19 18:58:49 -04:00
|
|
|
|
|
2015-09-19 20:21:55 -04:00
|
|
|
|
.. [22] https://jazzy.id.au/2010/09/22/cracking_random_number_generators_part_3.html
|
2015-09-19 18:58:49 -04:00
|
|
|
|
|
2015-09-19 20:21:55 -04:00
|
|
|
|
.. [23] https://mail.python.org/pipermail/python-ideas/2015-September/036077.html
|
2015-09-19 18:58:49 -04:00
|
|
|
|
|
2015-09-19 20:21:55 -04:00
|
|
|
|
.. [24] https://media.blackhat.com/bh-us-12/Briefings/Argyros/BH_US_12_Argyros_PRNG_WP.pdf
|
2015-09-19 18:58:49 -04:00
|
|
|
|
|
2015-09-19 20:21:55 -04:00
|
|
|
|
.. [25] https://mail.python.org/pipermail/python-ideas/2015-September/036157.html
|
2015-09-19 18:58:49 -04:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Copyright
|
|
|
|
|
=========
|
|
|
|
|
|
|
|
|
|
This document has been placed in the public domain.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
..
|
|
|
|
|
Local Variables:
|
|
|
|
|
mode: indented-text
|
|
|
|
|
indent-tabs-mode: nil
|
|
|
|
|
sentence-end-double-space: t
|
|
|
|
|
fill-column: 70
|
|
|
|
|
coding: utf-8
|
|
|
|
|
End:
|