Be careful with your random tokens
blog.meldium.com
blog.meldium.com
"A UUID is 128 bit long, and consists of a 60-bit time
value, a 16-bit sequence number and a 48-bit node
identifier.
The time value is taken from the system clock, and is
monotonically incrementing. However, since it is possible
to set the system clock backward, a sequence number is
added. The sequence number is incremented each time the
UUID generator is started. The combination guarantees that
identifiers created on the same machine are unique with a
high degree of probability."
Looking at the code, the node id is derived from the MAC, and the sequence number state is stored in /tmp or your home dir.In an era of vm's that are frozen and copied around between hosts, this seems like a spectacularly bad implementation. It's way to easy for this code to end up running from the same start state in such a situation, and as soon as that happens you'll have tons of exactly duplicated UUID sequences. I would hate to have to debug the mess that would produce. And that's aside from possible security issues.
Please do not use this gem. SecureRandom.uuid has a sane (and standard) implementation.
Your point about always using a new MAC when you thaw or duplicate a vm image is well taken.
I'm convinced that when code has cryptographic implications, people should not roll their own ad hoc weird solutions. Nearly every platform has a way of accessing high quality entropy. Version 4 random UUID's have been standardized for a while now. I don't understand the logic of using some "I invented this" implementation.
In the canonical representation, xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx, the
most significant bits of N indicates the variant (depending on the variant;
one, two or three bits are used). The variant covered by the UUID
specification is indicated by the two most significant bits of N being 1 0
(i.e. the hexadecimal N will always be 8, 9, A, or B).
In the variant covered by the UUID specification, there are five versions.
For this variant, the four bits of M indicates the UUID version (i.e. the
hexadecimal M will either be 1, 2, 3, 4, or 5).
The examples from the blog post don't appear to fit the RFC variant: 855ff330-5ce6-0130-d84d-12313d05011b
33aa4b00-5ce7-0130-d84d-12313d05011b
If the gem used [variant 1] version 4 UUIDs instead, this wouldn't be a problem (http://en.wikipedia.org/wiki/Universally_unique_identifier#V...): Version 4 UUIDs use a scheme relying only on random numbers. This algorithm
sets the version number as well as two reserved bits. All other bits are set
using a random or pseudorandom data source. Version 4 UUIDs have the form
xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx where x is any hexadecimal digit and y
is one of 8, 9, a, or b. e.g. f47ac10b-58cc-4372-a567-0e02b2c3d479.
Ruby 1.9 includes version 4 UUIDs as a built-in: SecureRandom.uuid. The author should consider using that instead. 5123ed3e43a9c
5123ed3e43c3c
5123ed3e43c44
5123ed3e43c4b
5123ed3e43c51
5123ed3e43c56
5123ed3e43c5c
5123ed3e43c62
5123ed3e43c6b
5123ed3e43c74Looking at the python implementation:
http://docs.python.org/2/library/uuid.html
def uuid4():
"""Generate a random UUID."""
# When the system provides a version-4 UUID generator, use it.
if _uuid_generate_random:
_buffer = ctypes.create_string_buffer(16)
_uuid_generate_random(_buffer)
return UUID(bytes=_buffer.raw)
# Otherwise, get randomness from urandom or the 'random' module.
try:
import os
return UUID(bytes=os.urandom(16), version=4)
except:
import random
bytes = [chr(random.randrange(256)) for i in range(16)]
return UUID(bytes=bytes, version=4)z-base-32[1] is a much human-friendlier alternative (while still being edible in nice discrete machine-word-chunks), although sadly, it's not supported by nearly as many stdlibs.
[1] http://philzimmermann.com/docs/human-oriented-base-32-encodi...
> `head -c 20 /dev/random`.unpack("H*").first => "0cc57e2664051b3fd803754fd538b83317c9057f"
It's reliably double the length of the input byte array, it isn't subject to transcription errors or special character conflicts, and hex conversions exist in every stdlib ever.