Let’s get one thing straight:
> UUIDs are not encryption. Not even a little.
They’re useful, yes. But treating them like a way to protect or hide data? That’s a dangerous myth.
Let’s unpack why UUIDs don’t make things secure — and what you should use instead.
🔐 What UUIDs Are Actually For
UUIDs (Universally Unique Identifiers) are designed to give us globally unique values without a central authority.
They're used for:
- Distributed database keys
- Log correlation
- Object identifiers
- Non-colliding session IDs
What they're not designed for:
- Hiding sensitive information
- Encrypting or protecting content
- Preventing enumeration or inference
⚠️ Common Misuses That Lead to Problems
1. “Let’s use UUIDs to hide internal IDs”
A common (bad) pattern:
/api/user/550e8400-e29b-41d4-a716-446655440000
Instead of:
/api/user/42
The assumption: “Users won’t be able to guess other UUIDs.”
Reality:
- UUIDv1 reveals timestamps and MAC addresses
- UUIDv4 can still be brute-forced or indexed
- Public UUIDs may show up in logs, emails, or URLs
This is obscurity, not security.
2. “We base64-encoded the UUID, so it’s safe now”
Encoding is not encryption.
import base64
import uuid
u = uuid.uuid4()
short = base64.urlsafe_b64encode(u.bytes).rstrip(b'=').decode()
Now it’s 22 characters. But it’s still just a UUID.
Anyone who knows how to decode Base64 can reverse it instantly.
3. “We only use the first 8 characters — good enough, right?”
Nope.
That’s a mere 32 bits of entropy — a brute-forceable range, even for modest bots.
- 8-char prefix collisions are common
- Guessing 32-bit tokens? Child’s play
🔍 Why This Fails as Security
UUIDs:
- Are not encrypted or hashed
- Have no integrity protection (tampering goes undetected)
- May leak structure or generation patterns
- Are often logged and replayed
They don’t:
- Prevent guessing
- Protect content
- Detect tampering
- Expire or validate access rights
🧠 What Should You Use Instead?
If you’re trying to protect data, you want:
✅ **Tokens with Signed Claims**
Use something like:
- JWTs (with HMAC or RSA signatures)
- Paseto (more modern, safer alternative to JWT)
- API keys with scoped access + expiration
These can carry:
- Expiry (
exp
) - Audience (
aud
) - Permissions (
scope
) - Tamper-proof signatures
✅ **Opaque Secure Tokens**
For one-time links or identifiers:
- Use
secrets.token_urlsafe(32)
(Python) - Use
crypto.randomBytes(32)
(Node.js) - Use
SecureRandom.getInstanceStrong()
(Java)
These are cryptographically secure and not guessable.
✅ **Encrypted Payloads**
If you're embedding data (e.g. emails or user IDs), encrypt it:
- AES encryption with authenticated mode (GCM)
- Store encrypted blob and a separate nonce/IV
🧪 Case Study: Password Reset Links
Bad:
/reset/uuidv4
Better:
/reset?token=secure-random-token
Best:
- Token includes expiry
- Is scoped to a specific email/user
- Is single-use and stored hashed (like passwords)
✅ Summary Matrix
Use Case | UUID OK? | Better Alternative |
---|---|---|
DB primary key | ✅ Yes | Use UUIDv4/UUIDv7 |
Public object IDs | ⚠️ Maybe | Add access controls |
One-time password link | ❌ No | Signed token or secure random |
API keys | ❌ No | Opaque bearer token |
Embedding sensitive info | ❌ No | Use encryption or signed JWT |
Final Thoughts
UUIDs are a fantastic tool for uniqueness, but not for secrecy.
They don’t prevent snooping, guessing, or abuse. If you’re treating UUIDs as a way to obfuscate or protect anything, it’s time to hit pause and reassess your architecture.
When in doubt, remember:
> If it’s not encrypted or signed, it’s not secure.
🔐 Use the right tool for the job — and UUIDs will keep doing what they do best: being unique, not secret.