debugsqlMinor
Primary key with randomly varying increments (so it cannot be guessed easily)
Viewed 0 times
cannotprimarywithvaryingrandomlyguessedincrementskeyeasily
Problem
I would like the primary keys to be auto-incremented and generated but in varying increments. For ex, if I have increment range as 100... then the auto generated keys would be something like below:
The data domains are often exposed via HTTP REST endpoints, and I would like the end users to not able to guess the primary keys by simply incrementing numbers.
I'm trying to avoid UUID/GUIDs if possible. My REST URLs are longer, often with parent-child identifiers. (Yes, it's avoidable but I prefer it for simpler testing/troubleshooting). So I prefer numbers as identifiers.
Is there any simpler solution that I'm not aware of? I'm using PostgreSQL but any generic solution is also fine.
- 20 (random number between 1 and 100)
- 30 (add random number 10 that's between 1 and 100)
- 113 (add random number 83 that's between 1 and 100)
- 118 (add random number 5 that's between 1 and 100)
- 217 (add random number 99 that's between 1 and 100)
- 220 (add random number 3 that's between 1 and 100)
The data domains are often exposed via HTTP REST endpoints, and I would like the end users to not able to guess the primary keys by simply incrementing numbers.
I'm trying to avoid UUID/GUIDs if possible. My REST URLs are longer, often with parent-child identifiers. (Yes, it's avoidable but I prefer it for simpler testing/troubleshooting). So I prefer numbers as identifiers.
Is there any simpler solution that I'm not aware of? I'm using PostgreSQL but any generic solution is also fine.
Solution
As your goal is for:
the end users to not able to guess the primary keys by simply incrementing numbers.
then rather than just a variable increment of your keys (so they have to search a few tens or hundreds of values), why not go for something completely nonlinear?
There's a function in the PostgreSQL wiki that should suit your needs, pseudo_encrypt.
It takes a sequential input and returns a pseudo-random non-repeating output.
Instead of your usual
you can instead manually make the sequence and assign ownership and define the column with a
There's an important caveat here, though. This technique won't work without modification for tables that have existing data, because the
the end users to not able to guess the primary keys by simply incrementing numbers.
then rather than just a variable increment of your keys (so they have to search a few tens or hundreds of values), why not go for something completely nonlinear?
There's a function in the PostgreSQL wiki that should suit your needs, pseudo_encrypt.
It takes a sequential input and returns a pseudo-random non-repeating output.
Instead of your usual
SERIAL PRIMARY KEY, which expands to:CREATE SEQUENCE mytable_colname_seq;
CREATE TABLE mytable (
colname integer PRIMARY KEY DEFAULT nextval('tablename_colname_seq'),
...
);
ALTER SEQUENCE mytable_colname_seq OWNED BY mytable;you can instead manually make the sequence and assign ownership and define the column with a
DEFAULT that calls the function over the sequence, e.g.:DEFAULT pseudo_encrypt(nextval('tablename_colname_id_seq'));There's an important caveat here, though. This technique won't work without modification for tables that have existing data, because the
pseudo_encrypt function might return a value that already exists in the table. It guarantees not to repeat its self, but knows nothing about anything already in the table. To copy with that, you could create a variant of pseudo_encrypt that took a second argument, the lowest ID it's allowed to return. If it calculated a lower ID, it'd just repeat the calculation with the next value from the sequence, discarding that ID.Code Snippets
CREATE SEQUENCE mytable_colname_seq;
CREATE TABLE mytable (
colname integer PRIMARY KEY DEFAULT nextval('tablename_colname_seq'),
...
);
ALTER SEQUENCE mytable_colname_seq OWNED BY mytable;DEFAULT pseudo_encrypt(nextval('tablename_colname_id_seq'));Context
StackExchange Database Administrators Q#71702, answer score: 4
Revisions (0)
No revisions yet.