Better random generation
Summary
Currently, LLNG relies highly on the standard perl random number generator (rand
).
However, as the perl documentation clearly states, rand is not to be used when its result has an impact on security
LLNG needs to use stronger random number generation primitives, possibly in the form of an internal library.
Why is this an issue
Strong randomness is required for an authentication system to be considered secure against motivated attackers. We should probably not be using a random generator that is highly discouraged for security use.
From a quick survey through the code, I found that Perl's rand
is used
- For password reset (::Portal::Lib::SMTP) through String::Random
- For OpenID registration (::Portal::Issues::OpenIDConnect) through String::Random
- For CSRF and OTP login token generation (::Portal::Lib::OneTimeToken)
- For Session ID generation (::Common::Apache::Session::Generate::SHA256)
- For password hashing in databases (::Portal::Lib::DBI)
- For TOTP registration (::Common::TOTP)
And I probably missed a few more. (SAML?)
As stated by the OWASP session management guide, session ID should use at least 64 bits of entropy. Perl's random is 48bits at most, is predictable, and concatenating the PID and date of session generation doesn't give much additional entropy anyway. A SHA256 of several predictable values is just as predictable.
Design proposition
I think the best solution is to implement an internal lib (::Common::Random ?) that provides random generation fonctions and that we would use in all the previously mentionned places. We could provide a remplacement rand
function, and embed a Random::String instance that is seeded with a proper random value.
This design would centralize all cryptographically sensitive operations in one convenient place, for easier review and update.
Random::String is, in recent versions, able to take a random function in a constructor argument, this would make it easy to integrate. Sadly the CentOS7 version of Random::String does not allow for this.
So far, I'm thinking about adding Crypt::URandom as a dependency. It's available on Debian and RedHat, it's fast, non blocking and pretty simple to use. And /dev/urandom is a very good source of entropy on recent versions of Linux, even for cryptographic purposes.
I'm not entirely sure how to implement the random-generation lib. Should it be just static methods? Or a Moose class from which all previously mentionned modules would inherit ?
I would like to be able to call the logging system from those functions (to warn the system admin if the RNG cannot be properly initialized), is that possible with a module that only provides static methods?
A possible API using only static methods would be:
- LemonLdap::NG::Common::Random::secure_rand : drop-in replacement for perl's rand
- LemonLdap::NG::Common::Random::secure_randregex (and)
- LemonLdap::NG::Common::Random::secure_randpattern: replacement for Random::String functions
- LemonLdap::NG::Common::Random::secure_id: generates a base64-encoded form token or session ID