[Python-Dev] BDFL ruling request: should we block forever waiting for high-quality random bits? (original) (raw)

Nick Coghlan ncoghlan at gmail.com
Wed Jun 15 19:26:07 EDT 2016


On 15 June 2016 at 16:12, Nathaniel Smith <njs at pobox.com> wrote:

On Wed, Jun 15, 2016 at 1:01 PM, Nick Coghlan <ncoghlan at gmail.com> wrote:

Victor has some additional technical details written up at http://haypo-notes.readthedocs.io/peprandom.html and I'd be happy to formalise this proposed approach as a PEP (the current reference is http://bugs.python.org/issue27282 ) I'd make two additional suggestions: - one person did chime in on the thread to say that they've used os.urandom for non-security-sensitive purposes, simply because it provided a convenient "give me a random byte-string" API that is missing from random. I think we should go ahead and add a .randbytes method to random.Random that simply returns a random bytestring using the regular RNG, to give these users a nice drop-in replacement for os.urandom.

That seems reasonable.

- It's not exactly true that the Python interpreter doesn't need cryptographic randomness to initialize SipHash -- it's more that some Python invocations need unguessable randomness (to first approximation: all those which are exposed to hostile input), and some don't. And since the Python interpreter has no idea which case it's in, and since it's unacceptable for it to break invocations that don't need unguessable hashes, then it has to err on the side of continuing without randomness. All that's fine.

But, given that the interpreter doesn't know which state it's in, there's also the possibility that this invocation will be exposed to hostile input, and the 3.5.2+ behavior gives absolutely no warning that this is what's happening. So instead of letting this potential error pass silently, I propose that if SipHash fails to acquire real randomness at startup, then it should issue a warning. In practice, this will almost never happen. But in the rare cases it does, it at least gives the user a fighting chance to realize that their system is in a potentially dangerous state. And by using the warnings module, we automatically get quite a bit of flexibility. If some particular invocation (e.g. systemd-cron) has audited their code and decided that they don't care about this issue, they can make the message go away: PYTHONWARNINGS=ignore::NoEntropyAtStartupWarning OTOH if some particular invocation knows that they do process potentially hostile input early on (e.g. cloud-init, maybe?), then they can explicitly promote the warning to an error: PYTHONWARNINGS=error::NoEntropyAtStartupWarning (I guess the way to implement this would be for the SipHash initialization code -- which runs very early -- to set some flag, and then we expose that flag in sys.something, and later in the startup sequence check for it after the warnings module is functional. Exposing the flag at the Python level would also make it possible for code like cloud-init to do its own explicit check and respond appropriately.)

A Python level warning/flag seems overly elaborate to me, but we can easily emit a warning on stderr when SipHash is initialised via the fallback rather than the operating system's RNG.

Cheers, Nick.

-- Nick Coghlan | ncoghlan at gmail.com | Brisbane, Australia



More information about the Python-Dev mailing list