Eg. for randomised algorithms you need a fast source of randomness.
Eg. for randomised algorithms you need a fast source of randomness.
Cryptographic random() is an extremely niche use case that you shouldn't be using unless you're writing your own crypto libraries. (Don't do that.)
Generally speaking, I'd agree the need for a cryptographicly secure random is niche in that it is limited to the implementation of specific libraries/functions that despite being widely used, should NOT be frequently re-implemented.
require(‘crypto’).randomBytes(15).toString(‘base64’)
Is this bad practice? Can you say more about why?Ok, maybe you're not worried about that scale; but I normally recommend 256-bit IDs in order to make sure that you don't need to worry about that possibility.
To answer the question as to when you should use cryptographic random(), ask yourself "What is the worst that could happen if someone guesses the result of random()?"
If the answer is "I don't know," go cryptrographic. You'll save your butt if you didn't know it was important.
If the answer is along the lines of "someone could impersonate a user, or leak information they shouldn't see," for the love of all that is holy, use cryptographic. This is basically every scenario where you are using random to generate an ID of some kind, and while it's only truly critical if that ID is all you need for validation, it does provide another layer of security even if you also require other information to match before giving out elevated access.
If the answer is "it defeats the algorithm I'm trying to do" (think something like ASLR, where you're randomizing the offsets of addresses so that attackers don't know where things are located), well, the reason why you need to use cryptographic should be blindingly obvious.
If the answer is instead "they can reproduce my results," well, you shouldn't use cryptographic in this case. And that's not a lot of cases: Monte Carlo simulations, testing, fuzzing are the obvious poster children for this category, and indeed reproducibility in these cases tends to be a highly valuable feature rather than an anti-feature.
Cryptographic random is almost never harmful to your application, and almost always provides some benefit in reducing guessability of your system. You should err on the side of using cryptographic random(), and only not use it when you are sure that guessability will not harm security in any way and you know that the cryptographic nature actively harms your application.
There are a lot of domains where security is a non-issue and performance is a huge concern (graphics, game logic, many kind of simulations, etc), and the default is the reverse... always just use the installed non-secure random() and if that's too slow consider other options.
Having a flag you can enable to warn about a non-secure random() usage, when it makes sense for your company/usage, sure. But banning it outright makes no sense, and the default behavior you want is very situational.
In that vein, the default random should be cryptographically-secure, with all the logic necessary to actually effect that security (e.g., not reusing seeds after a call to fork). You can also go ahead and provide an insecure random as well, but choosing the insecure random should always be something that the programmer has to go out of their way to do.
I guess it's a matter of perspective over who random() is for. I see random() as for the programmers who don't know what kind of randomness they need, and don't need to know that because they just need something 'random' not something secure. I expect the domain-experts to know that it's not what they need. In my mind it's not that random() is not secure, it's that using it for something it's not intended for is insecure.
When you need something to be fast, you better design it from the start to be fast. This is terrible advice for everything but some UI/web cases.
Speed is a feature. Not every feature can be just 'added' to existing code without changing most of it.
All of that is especially true for running simulations and the like. Whether these are fast is often determined by the architecture you decided on in the beginning.
Nowadays the world is full of libraries, frameworks, etc. that will never be as fast the competition, because they can't become fast without changing their APIs completely.
I completely agree that things which need to be fast should be designed structurally to be fast.
But which RNG function you use in a given function is about as far you can get from an architectural decision. You shouldn't need to refactor large swathes of your codebase to accommodate a substitution of one random number generator for a faster one.
I agree! But I also think a standard library should withstand a bit of abuse from people who don't know what they're doing.
I think this is a scenario that (a) isn't "extremely niche," and (b) warrants CSPRNGs.
The only possible justification for insecure randomness would be performance, but you'd need to generate a lot of random numbers to even be able to measure that.
Cryptographic randomness is typically slower than other forms of randomness.
In all of the programming I've done in my career, I've only needed cryptographic randomness a few times. For the rest, a fast pseudorandom number generator seeded by the clock was the correct choice.
I'd argue it's better to do the safe thing by default and switching to the faster alternative when you have proof you need it. Doing the fast thing by default and fixing security later is how we got Meltdown/Spectre.
I would argue that the default behavior should favor the novice and non-domain-expert. Should game programmers, graphic programmers, etc, be expected to know that they need to tune the performance of random() or should the domain-experts writing cryptographic algorithms be expected to understand the limitations of random() as it applies to their use-case?
The game programmer who needed better performance can "just" switch to a faster algorithm when the profiling calls for it (and if you don't notice it, well, no harm anyway).
The guy who just needed to generate some cryptographic keys? Rotate everything, and you had some pretty horrible hidden vulnerabilities in the meantime.
Yeah, that's the opposite of my experience. Often the libc random is too slow and limiting performance and I need to substitute something even faster.
But I agree that using something that is securely random by default is a good idea. People can substitute faster thing fit for their purpose if needed.
I don't really care for the browser application, if you made a TLS connection in the first place obviously you better have the randomness and might as well make random() use that, but someone explicitly using a CSPRNG in a native application is a huge code smell on the level of implementing your own crypto.
If you need a fast source of randomness, for some Monte Carlo algorithm for example, then you know this and can pick a deliberate pseudo-random generator that fits your needs.
I worked on a Monte Carlo path tracer. Early on we swapped out the random number generator from the standard random(). Initially not for speed, but due to the poor distribution.
After optimizing other areas it became a bottleneck and we swapped it out again for a faster one.
It turned out to be much less useful than that. So they got rid of it.
But short of saying "banned," any review of security critical code should include an explanation of where the random numbers are coming from and why they're trusted. Or in general for any code review: Why do you believe your numbers?
Though normal random() implementations are LCGs which have poor distributions when you either only look at the least significant bits or project them into multiple dimensions.
As a result they may make some randomized algorithms perform poorly!