Mike
Mike

Reputation: 173

what is a good way to encrypt a id in a url?

I've been looking at articles online about solutions to encrypting id's in a url. I've tried the basic encode decode but the problem i'm having when decoding it on the next page where I do a select where id = decoded id. It won't grab the proper user still from the table.

My link:

My link: 

<a href="sendContract.inc.php?id=<?php echo 
encrypt($customer_id) ?>"> View Contract </a>

sendContract.inc.php page:

$customer_id = $_GET['id'];
$decryped_id = base64_decode($customer_id);


$sql = "SELECT *
        FROM  bookings
        LEFT JOIN customers
        USING (customer_id)
        WHERE customer_id = '".$decryped_id."'
        ";

UPDATE: Now that I understand to that urlencode needed to be used, it works in the URL properly. The page is displaying a customers contract. And it's only unique to them. The contract link gets sent by email which is just a link with their customer_id (which is now encoded, decoded). I'm wondering what else can I do to secure their link and info? The contract is displayed as a PDF in the link (using tcpdf).

Upvotes: 6

Views: 34082

Answers (4)

ArtisticPhoenix
ArtisticPhoenix

Reputation: 21661

I would create a table specifically for this email operation. In said table I would have the id( auto-increment), user_id, create_date and hash. Then in the email you would pass the hash and look this up. The tie with the user_id is there but you are not exposing their actual account information. You can also delete this data after it is used, or after some amount of time has elapsed. This way the link will only work for limited amount of time. You could connect this table back to the user table with a very simple join INNER JOIN users ON {email_table}.user_id = user.id or what have you.

For the hash it could be as simple as

  md5($id . $create_date );

This would work just fine and serves only to make the url "pretty". Because you are saving the hash in the table as part of the row data, it dosn't need to be related to the data in that row at all. Basically it takes all the guess work out of it. I would also look into not exposing the '.php' extension. Most MVC frameworks can do this and it just make the url a bit cleaner like this

http://yoursite.com/sendContract/jsdkfe1902303kllllde

In my opinion the only way to really secure this is to limit how often and how long the url in the email could be used. You could also force them to login at the url, then you can be sure it is the account holder.

Upvotes: 1

Anthony
Anthony

Reputation: 231

It appears that you're not encrypting the ID, you're only encoding it in base64 which means that anyone can decode it. Here's an example showing a simple encoded string.

$str = 'This is an encoded string';
echo base64_encode($str);

This will output VGhpcyBpcyBhbiBlbmNvZGVkIHN0cmluZw==. If you notice, this string contains an equals sign. In fact, base64 encoded strings can contain "+", "/", or "=" which all need to be URL encoded before they can exist in a URL. Therefore, use the urlencode() function before passing it into the URL. For example,

$str = 'This is an encoded string';
echo urlencode(base64_encode($str));

will output VGhpcyBpcyBhbiBlbmNvZGVkIHN0cmluZw%3D%3D which is safe for URLs. Then when you need to decode the URL as in your example, you would do the following.

$customer_id = $_GET['id'];
$decoded_id = base64_decode(urldecode($customer_id));


$sql = "SELECT *
        FROM  bookings
        LEFT JOIN customers
        USING (customer_id)
        WHERE customer_id = '".$decoded_id."'
        ";

BUT REMEMBER, this implementation DOES NOT encrypt the ID, it is only encoded which means ANYONE can decode it.

Upvotes: 4

Chiến Ngh&#234;
Chiến Ngh&#234;

Reputation: 776

In order to avoid guessing Id by end user, I could suggest a way that takes use of hashed id. For example, you use MD5 as hash algorithm and database MySQL

Your url would be .../path?id={hashed_id}

When looking up at database your query will be

Select ...
From ...
Where MD5(ID_COLUMN) = {hashed_id}

By this way, you only expose hashed value of id to customer, not the id itself. Moreover, you dont need to maintain a secret key which could be potentially leaked out.

Upvotes: 0

Chris
Chris

Reputation: 136918

I like to use Hashids for this:

Hashids is a small open-source library that generates short, unique, non-sequential ids from numbers.

It converts numbers like 347 into strings like “yr8”, or array of numbers like [27, 986] into “3kTMd”.

You can also decode those ids back. This is useful in bundling several parameters into one or simply using them as short UIDs.

Hashids has been ported to many languages, including PHP. Here is an example from their website:

$hashids = new Hashids\Hashids('this is my salt');
$id = $hashids->encode(1, 2, 3);
$numbers = $hashids->decode($id);

Upvotes: 10

Related Questions