Don’t just randomize, truly randomize!
The state of web application cryptography has changed, and each development language provides its own way of working with it. I will touch on the current state of random number generation and the differences found with it within the Java and JavaScript development languages.
When designing and building web applications, security concerns obviously play a crucial role. The term security is pretty broad covering numerous areas including, but not limited to:
- input validation
- authentication
- session management
- parameter manipulation protection
- cryptography
In a previous DOD/government project, I was fortunate enough to work on a Java security component that dealt directly with that last-aforementioned security area: cryptography. Specifically, random number generation. Coming from a pure business Java development background, initially I had to take a step back from the technical design document and figure out how we wanted this web application to enforce confidentiality and integrity.
More specifically, how should the application keep secrets? How should we provide seeds for cryptographically-strong random values? Should we allow the browser to handle the random number generation or keep that on the back end? Lastly, what is the best way to create a random key for encryption?
Encryption and Randomness
In secure web application development, that last question plays a big role in the security benefit of using randomness. Some may say, “Hey, in regards to encryption, what about just using Base64 or UTF8 encoding?”. To put it bluntly… that’s old school! Nowadays, most security analysts don’t even consider those two solid, secure encryption methods anymore.
Other examples for the use of randomness could be the generation of random challenges upon logging in, creation of session IDs, or using secret keys for various encryption purposes. Regarding the last example, in order to generate such secret keys, an entropy pool is needed. An entropy pool that is unpredictable. This can be accomplished by verifying non-repeatable output of a cryptographically strong-random number generator (CSPRNG).
A rule of thumb I learned from various government security analysts I had the pleasure of working with was to steer clear of random numbers supplied by a third party.
Some may ask, “well, what’s wrong with http://random.org?” Nothing really… it does a great job of being a ‘true’ random number generator. Especially since it claims to generate randomness via atmospheric noise. However, if patterns are indeed detectable in this atmospheric noise, that sort of debunks its truly random claim. From a theoretical perspective, it’s a little difficult to find an unbiased measurement of physical sources of randomness. But I digress!
Can’t someone just use Random.org via SSL over HTTPS? Yes, but that’s not a good idea if you’re implementing this inside a crypto-secure system. Even the http://random.org site itself says to not use it for cryptography. Then again, outsourcing your random number generation kind of defeats the purpose of a secure system.
Java
Let’s take a look at what the Java language has to offer. From a Java server-side perspective, the Java language comes standard with the traditional Random class. This works fine for conventional, non-secure applications you may want randomized like a coin flipping game or a interactive card shuffler. This class has a fairly short period (2^48) given its seed = (seed * multiplier + 0xbL) & ((1L << 48) – 1). This will only generate a small combination of values.
To take a step back, a seed helps to recall, via your initial algorithm, the same sequence of random numbers that were generated.
Another limitation, at least for Java versions prior to 1.4, is that when using the default Random constructor to generate random numbers, it defaults to the current system time since January 1, 1970 measured in milliseconds. Thus, an outside user can easily figure out the random numbers generated if they happen to know the running time of the application.
SecureRandom to the rescue! SecureRandom, on the other hand, produces cryptographically-strong random numbers. CSPRNGS use a true random source: entropy.
For example, a user’s mouse clicks, mouse movements, keyboard inputs, a specific timing event, or any other OS-related random data. So it comes close to becoming a TRUE random number generator. I say close because at least they are not being generated by a deterministic algorithm.
But then again, theoretically, is anything ever truly random? Okay, nevermind that question. Keep in mind that SecureRandom uses PRNG implementations from other classes that are part of Java cryptographic service providers. For example, in Windows, the SUN CSP uses the SHA1PRNG by default. This is solid because utilizing this default SecureRandom() constructor, a user can retrieve a 128-bit seed. So based on its seed source, the chances of repeating are extremely less than the original java Random class.
A simple, straightforward implementation of a self-seeding SecureRandom generator:
// Very nice... // Instantiate secure random generator using the SHA1PRNG algorithm SecureRandom randomizer = SecureRandom.getInstance(“SHA1PRNG”); // Provide a call to the nextBytes method. This will force the SecureRandom object to seed itself. byte[] randomBytes = new byte[128]; randomizer.nextBytes(randomBytes);
On the other hand… The famous ‘Guarantee to be Random’ standard method:
// No bueno public int getRandomNumber() { return 7; // shhhh no one will know... teehee }
Bottom line: the most important thing to take into consideration is…. the seed! All psuedo-random number generators are deterministic if one knows the seed. Thus, the fact that SecureRandom is much better suited for working with a strong entropy source than Random is, gives it the advantage in a crytopgraphy environment. The downside is, the bigger the entropy needed, the worse the performance. Something to consider.
JavaScript
So what about JavaScript? Can the client-side be trustworthy enough to handle cryptography? Overall, how truly secure is the JavaScript language? Now that JavaScript and single page applications are becoming more and more popular, these are valid and important questions.
One of the most common insecurities on the client side is HTML injection, whereby an application may unknowingly allow third parties to inject JavaScript into its security context. Today, websites and many web applications need some sort of client-side encryption. Especially since browsers remain the tool of choice when interacting with remote servers. Fortunately for us JavaScripters, the most current browsers come packaged with sophisticated measures to combat these insecurities.
When collecting entropy, it’s obvious that JavaScript can very easily collect keyboard input, mouse clicks, etc., as well. However, it is difficult to provide entropy for determining a strong random number via a browser without encountering a usability drawback such as having to ask for some user interaction to assist in the seeding for a pseudo-random number.
That shouldn’t matter anyway, as JavaScript only comes with a Math.random() function that takes in no arguments. This Math.random() function comes automatically seeded similar to Java’s Random class, but what can one do to seed it manually? Nothing really. JavaScript doesn’t come with the ability to manually seed Math.random(). There are a few drop-ins, one of which is a popular RC-4 based one and is available on GitHub. It even has support for Node.js and Require.js.
Let’s keep in mind that all browsers come packaged with different random number generators. Chrome uses the ‘Multiply-with-carry’ generator. Firefox and IE use linear congruential generators (the Java Random class is modified using a linear congruential formula as well), so it would not be wise to use Math.random() alone as an only source of entropy. Let’s face it, this function is not cryptographically strong.
Some JavaScript crypto libraries do provide some help – one of which is CryptoJS. CryptoJS includes many secure cryptographic algorithms written in JavaScript. But let’s skip over the third party libraries and look at what Javascript has to offer.
Lately MDN has not disappointed. They are making strides in the cryptography world. For instance, the window.crypto.getRandomValues() function does pretty well. All that is needed with this entropy collection function is to pass in a integer-based TypeArray and the function will populate the array with cryptographically random numbers. Keep in mind, it is an experimental API, meaning it is still in ‘Working Draft’ status, but appears to only work in a few of the latest browsers that use strong (pseudo) random number generators. Here is a great link that shows browser compatibility with this particular function.
Conclusion
Until insecurities like code injection, side-channel attacks, and cross-site scripting are no longer a threat, it’s difficult to rely on JavaScript as a serious crypto environment. Hold on, though! I’m not proposing relying on full blown in-browser cryptography. One could open up a whole can of worms if the client side was to handle the majority of application security features.
However, this doesn’t mean that things won’t change in the future. Perhaps one day there will be a full cryptographic stack built into HTML/JavaScript. In addition, given the popularity of SPA and tools like Angular, I have a feeling window.crypto.getRandomValues() will be supported by all future browsers one day as well.
Until then, nothing beats generating random numbers on the back end. I’m looking on the bright side however, and I’m always keeping an eye out to see what’s in store for future SPA secure web development!
Reference: | Don’t just randomize, truly randomize! from our JCG partner Vince Pendergrass at the Keyhole Software blog. |
I think too often we look for the easiest/quickest security option as opposed to the best. But you know the easy/quick way is the first place hackers look (they want the easy/quick way in!). The more complicated you make things on your end the more you protect yourself in the long run.