Reputation: 1174
I've read a number of SO posts on this subject, but they seem to shrug it off as unimportant, so maybe if I give you my real world example that will affect the answer.
A system that manages contact lists and sends out emails, but allows the recipients to unsubscribe using a unique url.
Since this is a public page, it would be trivial for someone to just increment the ids and unsubscribe other users aswell.
I don't want to add a unique hash that I'd have to store in the database for each combination of user/contact/list.
What's the best approach to this? Are one of the following acceptable?
a) encrypt all the IDs and decrypt serverside
b) include a hash in the url based on the 3 IDs and a salt, and then confirm it server-side
Upvotes: 3
Views: 901
Reputation:
My view as someone who spent several years writing newsletter software (SAAS).
create a hash for each user\joiner\member sans store it with there other details. use that in a link for un-subscription.
I always had 2 hashes in my link, one was the newsletter sending hash, then you can track which one they unsubscribed from, as well as the per personal hash.
If you do want to expire the unsub link after a certain amount of time, as suggested by Thilo, you can use the date the newsletter was sent as determined by the, newsletter sending hash, but you will want to give them an alternative method, if the link is deemed to old. Such as another email
obligatory piece of code.
$hash = md5(uniqid(true));
store in db field with unique index. If you prefer you could add the email address in the mix to but uniqid() is designed to be, well, unique.
Upvotes: 2
Reputation: 7830
As I understand your question and comments, your requirements are
You are going to have an action on your server triggered by a http GET request, like
http://youremailsystem.tl/unsubscribe&user=12&contact=34&list=56
While your suggestion 1), encryption, adds the additional benefit of privacy (the URL does not give away what action with which parameters is performed), number 2) is the simpler approach.
You should use a MAC function to sign your URL parameters. The input will be your parameters that you want to sign plus a secret key, that never leaves your server.
$signature = hash_hmac('sha256', $url, $mysecretkey);
$url = $url . '&signature=' . $signature;
Which makes the signature part of the unsubscribe URL in your email.
http://youremailsystem.tl/unsubscribe&user=12&contact=34&list=56&signature=b1812e463a7
Whenever a GET request comes in, you can verify that the parameters have not been changed.
Rough code:
// extract sent signature from url:
$sent_signature = //substr($sent_url ...
// strip signature from URL:
$sent_url = //substr($sent_url ...
// repeat hashing:
$correct_signature = $signature = hash_hmac('sha256', $sent_url, $mysecretkey);
if( $sent_signature == $correct_signature ) {
// do the unsubscribe
}
Note that any URL can be called repeatedly, so make sure you never re-use any of your IDs, or else you would enable an ex-user to unsubscribe a newer user much later that now has their ID.
Upvotes: 3
Reputation: 1536
Use the email address along with user id (for possible duplicate addresses in your list(s)) in your hash for each user. store the hash along with the address in the db.
This way it is hard to reproduce the hash if you do not know the other users email.
Upvotes: 0
Reputation: 2408
Why the reluctance to create an unique token for each user? You DON'T have to create it for each combination you describe (user/contact/list), but just for the user you associate with an emailaddress.
Then use that single token for each action. And change it after it is used. Just generated 20 random numbers of something. It is easy and safe.
Upvotes: 1
Reputation: 262814
All mailing lists I have every used sent me a confirmation mail to unsubscribe with a presumably random and unique token in there that expires after a few hours.
I don't want to add a unique hash that I'd have to store in the database for each combination of user/contact/list.
You don't have to create them in advance or store them indefinitely. You can create random tokens when your receive an unsubscribe request, and delete it when done or expired.
Upvotes: 0