Reputation: 1911
I'm working on a function to send links to forms, en masse, trough our aplication's built-in email sender, and I'm planning to just send an url that contains the id and type of the entity it's been sent to, the id of the form and an identifier telling me in which database to look in (we have more than one databases with client data). I'm looking for a simple way to encode this information.
I thought about just sending an Id and keeping everything in the database, but since these emails will probably be sent en masse for marketting or loyalisation campaigns I think it's not a good idea.
I googled some encryption functions but the ones I tried sometimes returned results with illegal characters like "?" and "&" which wreck my link.
Upvotes: 2
Views: 5072
Reputation: 34123
In my home-grown CMS control panel, if you attempt to access a URL and are not logged in, you are redirected to a URL that looks like (for example): /?return=Epf7psjPeRHeEsCoa56xvvF9QiaT%2B02P5FUSbA0Ttl%2Bv3LalZ26sqzSAV6WrNKNWK%2FDD%2FngSbVjJ%2FyUuG9QIWA%3D%3D
Upon successfully authenticating, you will return to the correct URL. If you attempt to tamper with this blob of data, it will (with overwhelming odds) just kick you to the home page.
If that's what you're looking for, this is how I implemented it:
if ($_SERVER['REQUEST_URI'] !== '/') {
if (empty($_SESSION['cms_user_id_key_here'])) {
$encrypted = \Defuse\Crypto\Crypto::encrypt(
$_SERVER['REQUEST_URI'],
URL_KEY_CONST
);
header('Location: /?return='.urlencode(base64_encode($encrypted)));
exit;
}
}
And then, after a successful login:
if (isset($_GET['return'])) {
try {
$decrypted = \Defuse\Crypto\Crypto::encrypt(
base64_decode($_GET['return'],
URL_KEY_CONST
);
// Defense-in-depth; we always want a relative URL:
if ($decrypted[0] === '/') {
header('Location: '.$decrypted);
} else {
header('Location: /');
}
} catch (\Defuse\Crypto\Exception\CryptoException $e) {
header('Location: /');
}
exit;
}
What's this mysterious \Defuse\Crypto\Crypto::encrypt()
and \Defuse\Crypto\Crypto::decrypt()
, you ask? It's defuse/php-encryption of course.
You should, in almost all cases, prioritize utilizing a library that offers authenticated encryption over rolling your own unauthenticated encryption.
Upvotes: 0
Reputation: 48387
Since you don't want the information to be decodable by the client, that implies that you don't need a full URL - the thread of execution must return to your server for processing. In which case, why bother with the expense of encryption - just a assign a random number which references the original id (checking for collisions). Obviously the more sparse the random number set is, the less likely there will be collisions.
Upvotes: 1
Reputation: 39724
In all my applications I've encoded the URL's using base64_encode and base64_decode on the other side.
I believe it's the best way since you are not transmitting sensitive data to the client.
Otherwise you should save those URL's in the database (or maybe parameters) and just send an ID
Upvotes: 1
Reputation: 10423
If you need to encrypt, look for symmetric encryption like AES, then base64 encode the result.
If you only need to encode, then encode by Base64, it's your best shot.
Not in both cases you need to be aware that some browser URL length or web-server GET support are limited ... to some length (between 2000 to 80000 depending on browser and web-server)
Also consider how the link needs to be transmitted. Very long URL are not convenient. You can install very easily yourls.org or similar to shorten your URLs.
Upvotes: 1