Random numbers, ids and tokens
Random with a seed
A Random object with a seed produces the same sequence every time it is created with that seed. That is what a test or a simulation wants: a repeatable shuffle, not a surprise.
ruby -e 'r = Random.new(42); puts r.rand(100); r2 = Random.new(42); puts r2.rand(100)'
51
51
The top-level rand uses one shared generator and is seeded from the clock, so two runs differ. rand with a range and shuffle take the same seed idea when they are called on the object: r.rand(1..6), r.shuffle(names).
SecureRandom for tokens
A seeded generator is predictable by design, which makes it the wrong tool for a password reset link, an API key or a session id. The securerandom library draws from the operating system and is the one to use for anything a person must not guess:
ruby -e 'require "securerandom"; puts SecureRandom.uuid'
77090d45-73f6-4472-8fce-29fa49018570
ruby -e 'require "securerandom"; puts SecureRandom.hex(8)'
a5250daba79d920f
uuid gives the usual 36-character identifier; hex(8) gives 16 hex characters, one byte per two. urlsafe_base64(16) gives 22 characters that can sit in a URL without escaping.
What to watch for
Seeding a generator for a test is good; seeding it for a token is a
vulnerability. If a value protects something, it comes from
SecureRandom, never from rand.
A twelve-character hex token is 48 bits, which is plenty for a one-time
link and not enough for a long-lived key. Pick the length by what the
token protects, and store a hash of it rather than the token itself.
Next: Conditions
Article author: Arthur Isaev