> On Jun 11, 2016, at 5:16 PM, Guido van Rossum <gu...@python.org> wrote:
> 
> On Sat, Jun 11, 2016 at 1:48 PM, Donald Stufft <don...@stufft.io 
> <mailto:don...@stufft.io>> wrote:
> 
>> On Jun 11, 2016, at 3:40 PM, Guido van Rossum <gu...@python.org 
>> <mailto:gu...@python.org>> wrote:
>> 
>> Yeah, but we've already established that there's a lot more upset, rhetoric 
>> and worry than warranted by the situation.
> 
> Have we? There are real, documented security failures in the wild because of 
> /dev/urandom’s behavior. This isn’t just a theoretical problem, it actually 
> has had consequences in real life, and those same consequences could just 
> have easily happened to Python (in one of the cases that most recently comes 
> to mind it was a C program, but that’s not really relevant because the same 
> problem would have happened if they had written in Python using os.urandom in 
> 3.4 but not in 3.5.0 or 3.5.1.
> 
> Actually it's not clear to me at all that it could have happened to Python. 
> (Wasn't it an embedded system?)

It was a RaspberryPI that ran a shell script on boot that called ssh-keygen. 
That shell script could have just as easily been a Python script that called 
os.urandom via https://github.com/sybrenstuvel/python-rsa 
<https://github.com/sybrenstuvel/python-rsa> instead of a shell script that 
called ssh-keygen.

>> Actually the proposal for that was the secrets module. And the secrets 
>> module would be the only user of os.urandom(blocking=True).
> 
> I’m fine if this lives in the secrets module— Steven asked for it to be an os 
> function so that secrets.py could continue to be pure python.
> 
> The main thing that I want to avoid is that people start cargo-culting 
> whatever the secrets module uses rather than just using the secrets module. 
> Having it redundantly available as os.getrandom() is just begging for people 
> to show off how much they know about writing secure code. 


I guess one question would be, what does the secrets module do if it’s on a 
Linux that is too old to have getrandom(0), off the top of my head I can think 
of:

* Silently fall back to reading os.urandom and hope that it’s been seeded.
* Fall back to os.urandom and hope that it’s been seeded and add a 
SecurityWarning or something like it to mention that it’s falling back to 
os.urandom and it may be getting predictable random from /dev/urandom.
* Hard fail because it can’t guarantee secure cryptographic random.

Of the three, I would probably suggest the second one, it doesn’t let the 
problem happen silently, but it still “works” (where it’s basically just hoping 
it’s being called late enough that /dev/urandom has been seeded), and people 
can convert it to the third case using the warnings module to turn the warning 
into an exception.


>>  
>> * If you want to ensure you get cryptographically secure bytes, 
>> os.getrandom, falling back to os.urandom on non Linux platforms and erroring 
>> on Linux.
>> 
>> "Erroring" doesn't sound like it satisfies the "ensure" part of the 
>> requirement. And I don't see the advantage of os.getrandom() over the 
>> secrets module. (Either way you have to fall back on os.urandom() to 
>> suppport Python 3.5 and before.)
> 
> Erroring does satisfy the ensure part, because if it’s not possible to get 
> cryptographically secure bytes then the only option is to error if you want 
> to be ensured of cryptographically secure bytes. 
> 
> It’s a bit like if you did open(“somefile.txt”), it’s reasonable to say that 
> we should ensure that open(“somefile.txt”) actually opens ./somefile.txt, and 
> doesn’t randomly open a different file if ./somefile.txt doesn’t exist— if it 
> can’t open ./somefile.txt it should error. If I *need* cryptographically 
> secure random bytes, and I’m on a platform that doesn’t provide those, then 
> erroring is often times the correct behavior. This is such an important thing 
> that OS X will flat out kernel panic and refuse to boot if it can’t ensure 
> that it can give people cryptographically secure random bytes.
> 
> But what is a Python script going to do with that error? IIUC this kind of 
> error would only happen very early during boot time, and rarely, so the most 
> likely outcome is a hard-to-debug mystery failure.

Depends on why they’re calling it, which is sort of the underlying problem I 
suspect with why there isn’t agreement about what the right default behavior 
is. The correct answer for some application might be to hard fail and wait for 
the operator to fix the environment that it’s running in. It depends on how 
important the thing that is getting this random is.

One example: If I was writing a communication platform for people who are 
fighting oppressive regimes or to securely discuss sexual orientation in more 
dangerous parts of the world, I would want to make this program hard fail if it 
couldn’t ensure that it was using an interface that ensured cryptographic 
random, because the alternative is predictable numbers and someone possibly 
being arrested or executed. I know that’s a bit of an extreme edge case, but 
it’s also the kind of thing that people can might use Python for where the 
predictability of the CSPRNG it’s using is of the utmost importance.

For other things, the importance will fall somewhere between best effort being 
good enough and predictable random numbers being a catastrophic.


>  
> It’s a fairly simple decision tree, I go “hey, give me cryptographically 
> secure random bytes, and only cryptographically secure random bytes”. If it 
> cannot give them to me because the APIs of the system cannot guarantee they 
> are cryptographically secure then there are only two options, either A) it is 
> explicit about it’s inability to do this and raises an error or B) it does 
> something completely different than what I asked it to do and pretends that 
> it’s what I wanted.
> 
> I really don't believe that there is only one kind of cryptographically 
> secure random bytes. There are many different applications (use cases) of 
> randomness and they need different behaviors. (If it was simple we wouldn't 
> still be arguing. :-) 

I mean for a CSPRNG there’s only one real important property: Can an attacker 
predict the next byte. Any other property for a CSPRNG doesn’t really matter. 
For other, non kinds of CSPRNGs they want other behaviors (equidistribution, 
etc) but those aren’t cryptographically secure (nor do they need to be).

>>  
>> * If you want to *ensure* that there’s no blocking, then os.urandom on Linux 
>> (or os.urandom wrapped with timeout code anywhere else, as that’s the only 
>> way to ensure not blocking cross platform).
>> 
>> That's fine with me.
>>  
>> * If you just don’t care, YOLO it up with either os.urandom or os.getrandom 
>> or random.random.
>> 
>> Now you're just taking the mickey.
> 
> No I’m not— random.Random is such a use case where it wants to seed with as 
> secure of bytes as it can get it’s hands on, but it doesn’t care if it falls 
> back to insecure bytes if it’s not possible to get secure bytes. This code 
> even falls back to using time as a seed if all else fails.
> 
> Fair enough. The hash randomization is the other case I suppose (since not 
> running any Python code at all isn't an option, and neither is waiting 
> indefinitely before the user's code gets control).
> 
> It does show the point that there are different use cases with different 
> needs. But I think the stdlib should limit the choices.
> 
> -- 
> --Guido van Rossum (python.org/~guido <http://python.org/~guido>)


—
Donald Stufft



_______________________________________________
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com

Reply via email to