I expect this's been asked before but haven't really found an appropriate answer here and also don't have the time to come up with my own solution...
If we have a user table with int identity
primary key then our users have consecutive IDs while they register on the site.
The we have user public profile page on the site URL:
www.somesite.com/user/1234
where 1234 is the actual user ID. There is nothing vulnerable to see user's ID per se, but it does give anyone the ability to check how many users are registered on my site... Manually increasing the number eventually gets me to an invalid profile.
This is the main reason why I wand a reversible ID mapping to a seemingly random number with fixed length:
www.somesite.com/user/6123978458176573
Can you point me to a simple class that does this mapping? It is of course important that this mapping is simply reversible otherwise I'd have to save the mapping along with other user's data.
GUIDs are slower to index search them because they're not consecutive so SQL has to scan the whole index to match a particular GUID instead just a particular calculated index page...
If I'd have ID + GUID then I would always need to fetch original user ID to do any meaningful data manipulation which is again speed degradation...
A mathematical reversible integer permutation seems the fastest solution...
I would 100% go with the "Add a GUID column to the table" approach. It will take seconds to generate one for each current user, and update your insert procedure to generate one for each new user. This is the best solution.
However, if you really dont want to take that approach there are any number of obfuscation techniques you could use.
Simply Base64 encoding the string representation of your number is one (bad) way to do it.
static public string EncodeTo64(string toEncode)
{
byte[] toEncodeAsBytes
= System.Text.ASCIIEncoding.ASCII.GetBytes(toEncode);
string returnValue
= System.Convert.ToBase64String(toEncodeAsBytes);
return returnValue;
}
static public string DecodeFrom64(string encodedData)
{
byte[] encodedDataAsBytes
= System.Convert.FromBase64String(encodedData);
string returnValue =
System.Text.ASCIIEncoding.ASCII.GetString(encodedDataAsBytes);
return returnValue;
}
Bad because anyone with half an ounce of technical knowledge (hackers/scriptkiddies tend to have that in abundance) will instantly recognise the result as Base64 and easily reverse-engineer.
Edit: This blogpost Obfuscating IDs in URLs with Rails provides quite a workable example. Converting to C# gives you something like:
static int Prime = 1580030173;
static int PrimeInverse = 59260789;
public static int EncodeId(int input)
{
return (input * Prime) & int.MaxValue;
}
public static int DecodeId(int input)
{
return (input * PrimeInverse) & int.MaxValue;
}
Input --> Output
1234 --> 1989564746
5678 --> 1372124598
5679 --> 804671123
This follow up post by another author explains how to secure this a little bit more with a random XOR, as well as how to calculate Prime
and PrimeInverse
- ive just used the pre-canned ones from the original blog for demo.
Use UUIDs
Make another column in the user table for, e.g. 64 bit integers, and fill it with a random number (each time a new user registered - generate it and check it's unique). A number looks better than UUID, however a bit more coding required.
Use maths. ;) You could generate pair of numbers X
, Y
such as X*Y = 1 (mod M)
. E.g. X=10000000019L
, Y=1255114267L
, and M=2^30
. Then, you will have two simple functions:
.
long encode(long id)
{ return (id * X) & M; }
long decode(long encodedId)
{ return (encodedId * Y) & M; }
It will produce nearly random encoded ids. It's easy, but hackable. If someone would bother to hack it, he will be able to guess your numbers and see encoded values too. However, I am not completely sure which complexity it is, but as I remember it's not very easy to hack.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With