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...
<
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.
May I suggest that you use a UUID instead. This could be indexable and generated within a stored procedure when you add a new user to the database. This would mean either adding a new column to the database table or a new table containing UUIDs but with the User ID as related key.
edit
If you really want to avoid GUIDs then why not use the users "username" whilst they access their profile page. After all I imagine that you don't assign a user an ID until they have entered valid information and that data has been saved into the database.
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.