8

My PHP Application uses URLs like these:

http://domain.com/userid/120
http://domain.com/userid/121

The keys and the end of the URL are basically the primary key of the MySQL database table.

I don't want this increasing number to be public and I also don't want that someone will be able to crawl the user profiles just by interating the Id.

So I want to encrypt this Id for display in a way I can easily decrypt it again. The string shouldn't get much longer.

What's the best encryption method for this?

2
  • 2
    I would suggest to use the username in the url, like domain.com/user/jsmith. It's more web 2.0, you keep your primary key secret and you don't overload the server by encrypting/ decrypting the primary key Commented Dec 13, 2010 at 14:19
  • I'm really trying to resist the urge to say you're doing it wrong. First, who cares if the user profiles can be crawled? Google will find them anyway, so there's no real way you can stop it short of putting them behind a login (and even then, someone who wants the info will get it). Secondly, why use the id in the url? Why not use the unique user name (the username is unique, isn't it?)? It gives more semantic meaning than the number, and shouldn't be that much less efficient (assuming you have UNIQUE set on the username column)... Commented Dec 13, 2010 at 14:22

9 Answers 9

7

Simple Obscuring: Base64 encode them using base64_encode.
Now, your http://domain.com/userid/121 becomes: http://domain.com/userid/MTIx
Want more, do it again, add some letters around it.

Tough Obscuring: Use any encryption method using MCrypt library.

Sign up to request clarification or add additional context in comments.

5 Comments

how would you distinguish between a simple and tough encryption?
@Sandeepan, Simple would be easily to decrypt and does not use a key but tough one is hard to decrypt.
how would you distinguish between easy to decrypt and hard to decrypt ? ;-)
@Victor: In this case, given a URL, simple to decode would require no additional information, tough to decode requires additional information (e.g. the key, any IV used, etc.) or a cryptographic attack.
This helps me on a current project. base64_encode was the idea I was looking for. I don't need a real secure solution from the public or I wouldn't use this. Only certain logged in member would have access to the page anyway and now I won't have to make a gazillion different user groups to separate access. And it will keep these non-tech-savy users' noses out of each others stuff––stuff that isn't really a security concern in the first place. Thanks for the tip.
6

A better approach (from a usability and SEO perspective) would be to use a unique phrase rather than an obscured ID. In this instance the user's user name would seem an ideal solution, and would also be un-guessable.

That said, if you don't want to use this approach you could just use a hash (perhaps md5) of the user's user name which you'd store in the database along with their other details. As such, you can just do a direct lookup on that field. (i.e.: Having encrypt and decrypt part of the URL is probably overkill.)

Comments

4

You have a variety of choices here:

  • Generate and store an identifier in the database. It's good because you can then have readable keys that are guaranteed to be unique. It's bad because it causes a database schema change, and you have to actually query that table every time you want to generate a link.

  • Run an actual key-based encryption, for instance based on PHP's MCrypt. You have access to powerful cryptographic algorithms, but most secure algorithms tend to output strings that are much longer than what you expect. XOR does what you want, but it does not prevent accessing sequential values (and the key is pretty simple to determine, given the a priori knowledge about the numbers).

  • Run a hash-based verification: instead of using 121 as your identifier, use 121-a34df6 where a34df6 are the first six characters of the md5 (or other HMAC) of 121 and a secret key. Instead of decoding, you extract the 121 and recompute the six characters, to see if they match what the user sent. This does not hide the 121 (it's still right there before the hyphen) but without knowing the secret key, the visitor will not be able to generate the six characters to actually view the document numbered 121.

  • Use XOR with shuffling: shuffle the bits in the 30-bit identifier, then apply the XOR. This makes the XOR harder to identify because the shuffle pattern is also hidden.

  • Use XOR with on-demand keys: use fb37cde4-37b3 as your key, where the first part is the XOR of 121 and md5('37b3'.SECRET) (or another way of generating an XOR key based on 37b3 and a secret).

Don't use base64, it's easy to reverse engineer: if MTIx is 121, then MTIy is 122 ...

Ultimately, you will have to accept that your solution will not be secure: not only is it possible for users to leak valid urls (through their browser history, HTTP referer, or posting them on Twitter), but your requirement that the identifier fits in a small number of characters means a brute-force attack is possible (and becomes easier as you start having more documents).

Comments

1

Simplest but powerful encryption method: XOR with a secret Key. http://en.wikipedia.org/wiki/XOR_cipher No practical performance degradation.

Base64 representation is not an encryption! It's another way to say the same.

Hope this helps.

1 Comment

Thank you for the base64 comment which is not an encryption. That needed to be said!
0

Obscuring the URL will never secure it. It makes it harder to read, but not much harder to manipulate. You could use a hexadecimal number representation or something like that to obscure it. Those who can read hex can change your URL in a few seconds, anyway:

$hexId = dechex($id); // to hex
$id = hexdec($hexId); // from hex

Comments

0

I'd probably say it's better indeed to just create a random string for each user and store that in your database than to get one using hash. If you use a common hash, it's still very easy to iterate over all pages ;-)

I would write this in comments, but don't have the rep for it (yet?).

Comments

0

When user click on a link you should not use primary key, You can use the pkey in a session and get it from that session. Please do not use query string....

Comments

-1

generate an unique string for each user and use it in your urls

http://domain.com/user/ofisdoifsdlfkjsdlfkj instead of http://domain.com/userid/121

Comments

-1

you can use base64_encode and base64_decode function for encrypt and decrypt your URLS

3 Comments

+1 to balance whoever gave you the down vote. Your's isn't a bad answer
The downvote wasn't mine, but base64_(en|de)code is not (en|de)cryption. It would obscure the id number slightly, but in a predictable fashion.
base64 makes no encrypting, any developer will easily recognize and be able to decrypt the value, and hence be able to crawl the pages.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.