views:

153

answers:

4

I am creating a script that takes a list of names and email addresses and sends an email inviting them to register for our department's secure website. The list of names and emails are available on a public facing page on the same site. I need a way to give them a unique token that will identify them when they follow a link in the email to the page to register the account. The user will only be using the token once, to create the account and set their initial password.

What would be the best method to generate the token? A random string stored in a database? A hash generated from the user information and some salt? Something else? I understand that the security of this method depends on the privacy of the individual email invite, which is slight I understand.

+5  A: 

There are many different hash algorithms. You could look at this link to see if one will work better for you, since you don't need a secure hash. You could also look up to see how SSL lib will generate an 8 character md4 hash.

http://www.partow.net/programming/hashfunctions/#top

James Black
A: 

Check out gperf.

GNU gperf is a perfect hash function generator. For a given list of strings, it produces a hash function and hash table, in form of C or C++ code, for looking up a value depending on the input string. The hash function is perfect, which means that the hash table has no collisions, and the hash table lookup needs a single string comparison only.

And also CMPH - C Minimal Perfect Hashing Library

There are several related SO questions:

Mitch Wheat
Thanks for the answers, it seems I was asking the wrong question.
tvanover
Whoever just downvoted, thanks for the 'revenge' downvote
Mitch Wheat
A: 

Why not just assign a random 64-bit number to send with the user's id. Take the 64-bit number, break it into 5-bit chunks, and use each 5-bit chunk to index into a 32-character alphabet: 23456789ABCDEFGHJKLMNPQRSTUVWXYZ (conveniently omitting 01IO). With a 64-bit number and 5-bits/code (except the last one) you get a 13 character slug to use to identify the user. You could pad it with 2 random characters to give 3 groups of 5 characters if you wanted.

Make the id and the slug part of the login url. Check the value of the slug stored with the id in the database to make sure they are the same. I think for most purposes this would be a large enough value to make it extremely hard to guess -- the number is random after all -- which slug goes with which user id. Using a cryptographically strong random number generator, I would think it would be highly unlikely that you'd even get repeat numbers for any of your users.

It might look like:

http://example.com/activate?userid=bgates&validate=GY45M-RHQBN-32GYM

Using a hash of known values might actually make it easier for someone to guess the correct code than using a random number. Using a hash one only has to guess which bits you're using and run them through various hash algorithms. If someone is able to piece these together, say given a few examples and enough time to try various combinations, then all they have to do to crack someone's code is determine the (probably) commonly known attributes for a given person and use those to impersonate them and create an account. With a strong random number assigned to each individual they're only left with a brute force attack.

tvanfosson
Very good point about hashes being possible to "reverse engineer". And if you're really concerned about people guessing the random numbers, add some protection into it that deletes their account if they try to authenticate with the wrong token 10 times, or something like that. Then it's pretty much impossible to impersonate anyone.
Chad Birch
If you really do need to use a hash based on "known values," you can salt the hash, which makes it exceedingly hard to guess. E.g. sha1("6b34ff3b93d0ebd46d3e" . $username . "8ca97cf1ae342d340f26"). Of course, if the salt is leaked, then you're hosed. But yeah, it's better to generate a random value unrelated to the user info, and store that random value in a database.
dirtside
+2  A: 

Why does it need to be a hash in particular? Just put the new user's username as part of the link, and randomly generate an authentication token of whatever length you want, and store that in the database, linked to their username, until they authenticate.

So the link they get in the email is something like:

http://domain.com/confirm.php?user=Chad&t=AB14CD05

It really doesn't matter if there are any collisions, it's a fairly low risk event anyway. What could go wrong anyway, someone else could... confirm their email address for them? What are you concerned about? Perhaps if you explain the whole process in a little more detail, I'd understand your requirements better.

Chad Birch
I think that I do need to change the question. Your right, I should not be finding the best way to create a hash to meet my needs but I should be asking what would be the solution for the overall problem of authenticating when the only semi-private identifier is the token I send in the inviting email. Should I amend my question or should I post a new one?
tvanover