About
This page is about how to obfuscate / protect a internal id. So that even if they are public, they cannot be guessed.
Purpose
This is mostly used to prevent guessing your data.
Estimate business data
For instance, you can estimate the number of orders
https://example.com/orders?orderid=7865
Prevent DDOS attack - Prevent id forgery
You can prevent a ddos.
Because this is not shown as a sequence, the attacker cannot guess or create the ids.
- Bad ids are catched before hitting the database.
- Good ids are generally fetch once and put in cache (meaning that if there is repeated requests in a short period of time, the data will not hit the database but the cache).
Prevent information leaking
Because this is not shown as a sequence, you can prevent a scanning of public data and extraction of information. If you have a public page, the attacker cannot guess, the next id.
Encryption Method
The id are encrypted using a symmetric cipher with a secret and a salt because there is only one party, you.
Example:
Stronguest | Description | Note | |
---|---|---|---|
strong | key | Advanced Encryption Standard (AES) | generally with a hash-based message authentication code (HMAC) to protect the IDs from being altered by the attacker |
less strong | alphabet shuffle | the most known example is the hashid library |
Library
HashId
- Number to text with salt: https://hashids.org/ - YouTube-like ids from numbers - Use it when you don't want to expose your database ids to the user.
Example:
let minimalHashLength = 8;
let hashAlphabet = "abcdefghijklmnopqrstuvwxyz1234567890";
let hashids = new Hashids("this is my salt", minimalHashLength, hashAlphabet)
let encode1 = hashids.encode([1]);
let decode1 = hashids.decode(encode1);
console.log(`The value 1 encoded is: ${encode1}`);
console.log(`The encoded value ${encode1} decoded is: ${decode1}`);
- Hashid will return an empty array if it can't decode
let badvalue = "badvalue";
let decodedBadValue = hashids.decode(badvalue);
console.log(`The bad value (${badvalue}) decoded is an empty array: ${decodedBadValue}`);
- You can encode multiple value
let multipleValues = [1,2];
let multipleValuesEncoded = hashids.encode(multipleValues);
console.log(`Mutliple values (${multipleValues}) are encoded to ${multipleValuesEncoded}`);
let multipleValuesDecoded = hashids.decode(multipleValuesEncoded);
console.log(`Mutliple values encoding (${multipleValuesEncoded}) are decoded to ${multipleValuesDecoded}`);
- Because you can encrypt by part, you can also encode an Uuid
let uuidString = uuid.v4();
let uuidByteArray = uuid.parse(uuidString); // 16 bytes array
let dataViewByteArray = new DataView(uuidByteArray.buffer, 0);
let uuidTimeLow = dataViewByteArray.getUint32(0);
let uuidTimeMid = dataViewByteArray.getUint16(4);
let uuidTimeHighAndVersion = dataViewByteArray.getUint16(6);
let uuidClokSeq = dataViewByteArray.getUint16(8);
let uuidNode1 = dataViewByteArray.getUint32(10);
let uuidNode2 = dataViewByteArray.getUint16(14);
let uuidHashed = hashids.encode([uuidTimeLow,uuidTimeMid,uuidTimeHighAndVersion,uuidClokSeq,uuidNode1, uuidNode2]);
console.log(`The uuid ${uuidString} has been encoded to ${uuidHashed} of length ${uuidHashed.length}`);
Optimus
Optimus:
- obfuscates id number into integer id (no text)
- is based on Knuth's integer hash method
Implementation:
- Go.
Id Mask
Specific Algorithm
Siv (Synthetic IV)
SIV solves both:
- the key-wrap problem (deterministic authenticated-encryption)
- and the problem of conventional (two-pass, nonce-based) authenticated-encryption
It produces:
- a ciphertext having the same length as the plaintext
- and a synthetic initialization vector.
AES-SIV ciphertexts are the size of the input + 128-bits (SIV tag), because it uses AES-CTR encryption.
Siv paper in 2006 by Phil Rogaway “A Provable-Security Treatment of the Key-Wrap Problem” 2) described in RFC 5297