5

I have a link which needs to be generated so that it can be placed in an email. When the user clicks on this link, the system is meant to match the code sent in the email to a user, so it can pull up the records for that user.

However, I am not quite sure which encryption/hashing method to use. For the login for the admin system on this site, I use PBKDF2 in the database for the password (with salting) and AES encryption when it is sent to the session variables, but I don't know if the characters used by PBKDF2 & AES are url compatible.

Basically, I need the best method of hashing/generating a random code for storage in the database and an encryption method so that I can place a year and the code (which I previously mentioned) in a url. I am using PHP and MySQL if that helps.

What do you guys think?

Phil Young
  • 1,334
  • 3
  • 21
  • 43
  • No worries there: a URL can represent any character, even multi-byte ones, as long as it's properly encoded. – netcoder May 09 '12 at 09:15

2 Answers2

10

The output of most encryption (or hashing, etc.) routines is arbitrary binary data, which cannot be safely included in a URL without encoding it.

As eggyal notes, simply using urlencode() on the data should be enough. However, standard URL-encoding may not be the most compact way to encode random binary data. Base64 encoding would be more efficient, but unfortunately is not completely URL-safe due to its use of the + character.

Fortunately, there exists a standardized URL-safe variant of the base64 encoding, specified in RFC 4648 as "base64url". Here's a pair of functions for encoding and decoding data using this encoding in PHP, based on this answer by "gutzmer at usa dot net":

function base64url_encode($data) {
    return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}

function base64url_decode($data) {
    return base64_decode(strtr($data, '-_', '+/'));
}

(I've simplified the decoding function a bit, since at least current versions of PHP apparently don't require = padding characters in the input to base64_decode().)


Ps. For securely generating the random tokens in the first place, see e.g. this question.

Community
  • 1
  • 1
Ilmari Karonen
  • 49,047
  • 9
  • 93
  • 153
  • What about using php's base64_encode() and base64_decode() functions if we are using base64? – Phil Young May 09 '12 at 13:42
  • @Phil: I _am_ using them, but they need to be combined with `strtr()` to produce URL-safe output. – Ilmari Karonen May 09 '12 at 13:44
  • @llmari what is the best way to store the pseudo random bytes you get from that link for generating the code? – Phil Young May 11 '12 at 14:06
  • @Phil: Store where? In PHP, an ordinary string variable will do just fine. In MySQL, a `BINARY(16)` column would be suitable. – Ilmari Karonen May 11 '12 at 22:21
  • Indeed I found that if I do http://myserver/controller/myaction/myId and myId is a hash with the "+" sign or some other characters, even if I do encodeUriComponent when building the url, aspnet mvc complains about this. So indeed here the solution should be to change your hashing algorithm – Kat Lim Ruiz Mar 30 '15 at 20:33
6

Perform the hash however you wish, then urlencode() the result prior to inserting it into the URL.

eggyal
  • 122,705
  • 18
  • 212
  • 237