Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

A good practice for creating human-typable, non-sequential unique id's

Tags:

php

mysql

I need to create a unique id for our users. I don't want to use an auto_incrementing id, because I don't want users to be able to guess how many users we have, or what the growth rate is.

A UUID is not really an option either, because users will have to re-type the id on a smartphone.

So I'm hoping I can reduce 'brute-forcing' the database as much as possible to find unused ids. What would be a smart way to go about this?

Thank you!

like image 283
Evert Avatar asked Feb 27 '12 12:02

Evert


1 Answers

OK, i'll give it another try. Your goals are:

  • obfuscate the increment rate of your identifier - not sequential, not guessable, not calculatable
  • have that still "usable" for smartphone users, thus long UUIDs or SHA1 hashes are out of scope
  • avoid necessity of random guesses / bruteforce apporaches to the database
  • still have good database performance with your Foreign Keys

To still have good performance in your database you should keep a standard auto_incrementing integer for your PK. Note that InnoDB orders the rows based on the PK (see "InnoDB clustered Index"), so if you use some kind of magic hash as PK, you will end up with a lot of reordering in your clustered index, giving bad write performance.

I suggest to use an encryption algorithm (encryption, not hashing) to encrypt and decrypt the ID you want to obfuscate. Also, for best obfuscation, you want to use a minimum length for the resulting string. The resulting string should be still usable, so you must use something like base64 to present it user readable.

Try this encryption example:

function my_number_encrypt($data, $key, $base64_safe=true, $minlen=8) {
        $data = base_convert($data, 10, 36);
        $data = str_pad($data, $minlen, '0', STR_PAD_LEFT);
        $data = @mcrypt_encrypt(MCRYPT_BLOWFISH, $key, $data, MCRYPT_MODE_CBC);
        if ($base64_safe) $data = str_replace('=', '', base64_encode($data));
        return $data;
}

function my_number_decrypt($data, $key, $base64_safe=true) {
        if ($base64_safe) $data = base64_decode($data.'==');
        $data = @mcrypt_decrypt(MCRYPT_BLOWFISH, $key, $data, MCRYPT_MODE_CBC);
        $data = base_convert($data, 36, 10);
        return $data;
}

$key = "my super secret magic bytes";

$id = 12345678; // obtain_normal_key_from_mysql();

// give ID to user
$enc = my_number_encrypt($i, $key);

// get ID from user
$dec = my_number_decrypt($enc, $key);
// fetch from database using normal ID -> 12345678

// demo code
for($i=10000; $i<10050; $i++) {
        $enc = my_number_encrypt($i, $key);
        $dec = my_number_decrypt($enc, $key);
        echo "$i -> $enc -> $dec", PHP_EOL;
}

Demo result:

10000 -> 1RXK468NYes -> 10000
10001 -> QdEov5mjMPA -> 10001
10002 -> 2gsgzWJgD+8 -> 10002
10003 -> 2zwPwhqr9HI -> 10003
10004 -> Xq+kDh1UFuM -> 10004
10005 -> wfwv6TrW9xY -> 10005
10006 -> 1Lck1L0HJ/U -> 10006
10007 -> v+3YY2zfL1A -> 10007
10008 -> 5AmGlqD8byM -> 10008
10009 -> pZBIpPnKXHU -> 10009
10010 -> CAeWdKGkk8c -> 10010
10011 -> fYddnLOSK6U -> 10011
10012 -> na8Ry0erHv8 -> 10012
10013 -> zxNj+ZJVMBY -> 10013
10014 -> gWJWC9VulZc -> 10014
10015 -> 5pR9B79eM/E -> 10015
10016 -> MQtpBhpzHRA -> 10016
10017 -> dW+3nejBEIg -> 10017
10018 -> znB/feM6104 -> 10018
10019 -> RtdRwwRyEcs -> 10019
10020 -> 4cW/OWT140E -> 10020
10021 -> dIvK9VjOevg -> 10021
10022 -> QxLdfrucc/Y -> 10022
10023 -> M0KN3sX10Gs -> 10023
10024 -> 827yFJyDCG4 -> 10024
10025 -> JF/VRj92qL8 -> 10025
10026 -> IXTvn/SCzek -> 10026
10027 -> L4nFwvhgwX8 -> 10027
10028 -> z0lve9nhgDA -> 10028
10029 -> m/UBgZzfIXo -> 10029
10030 -> IfWcrLKTHXk -> 10030
10031 -> n/jPFwKR/9A -> 10031
10032 -> j1mm2kbeWl0 -> 10032
10033 -> cm7mOQMVa6k -> 10033
10034 -> jCUuweEyRME -> 10034
10035 -> LDaMcOWKxjg -> 10035
10036 -> Zcrd5XzhhIk -> 10036
10037 -> j0Yg/fCjyAA -> 10037
10038 -> /LmlvRHmmmg -> 10038
10039 -> t0juuzGSKs4 -> 10039
10040 -> 9CoRCVXaak4 -> 10040
10041 -> tFmImR4j0JM -> 10041
10042 -> nI3Thy51hLg -> 10042
10043 -> mTCJh0/h2mE -> 10043
10044 -> S196xdyb3Os -> 10044
10045 -> ItOyUp+J4Q4 -> 10045
10046 -> DL87SidiOLM -> 10046
10047 -> d+Nw3xBqV44 -> 10047
10048 -> 3YzVelaC4uI -> 10048
10049 -> fAUJVOl6PaU -> 10049
like image 150
Kaii Avatar answered Oct 12 '22 22:10

Kaii