Does this registration security procedure for my website make any sense?
May 30, 2012 8:57 AM Subscribe
Does this registration security procedure for my website make any sense?
I know there are hundreds of web pages out there with information about security but its quite intimidating for someone like myself who hasn't ever had to do this before. So i'm taking it to the hive.
I've got a website with a registration form. User fills out the form, chooses a username and password, presses submit and my php page makes sure the form is all good and sends it onto the DB.
From that point, I want to send an email to the user with a URL that he must click on to activate the account. I want this URL to be unhackable and unguess-able. I started reading into checksums and MD5 and think this possibly sounds like the way to go. Heres my solution.. would appreciate if you professionals out there can critique it and tell me if i'm doing this ass backwards.
So... Once the DB gets the form data, it creates a temporary user record in an "on deck" table with a timestamp that can be used to determine when to delete the record if the user never follows up. Then I would have a function generate a random string of say 25 characters and store that in another field. Then I would create an MD5 checksum using the MD5 checksum of the user password + the random string + the temporary user_id as inputs. This string will then be used to create a URL with a unique POST variable and using the user_id as a prefix. Something like www.myurl.com/register.php?reg=[user_id][checksum]
Once the user clicks on the URL, the database finds the record with the user_id passed to it, then re-generates the checksum using the same inputs it has stored in the record and compares it to the checksum passed in the URL. If it passes, i move the temporary record to the permanent user table, delete the record and voila! (???)
I know there are hundreds of web pages out there with information about security but its quite intimidating for someone like myself who hasn't ever had to do this before. So i'm taking it to the hive.
I've got a website with a registration form. User fills out the form, chooses a username and password, presses submit and my php page makes sure the form is all good and sends it onto the DB.
From that point, I want to send an email to the user with a URL that he must click on to activate the account. I want this URL to be unhackable and unguess-able. I started reading into checksums and MD5 and think this possibly sounds like the way to go. Heres my solution.. would appreciate if you professionals out there can critique it and tell me if i'm doing this ass backwards.
So... Once the DB gets the form data, it creates a temporary user record in an "on deck" table with a timestamp that can be used to determine when to delete the record if the user never follows up. Then I would have a function generate a random string of say 25 characters and store that in another field. Then I would create an MD5 checksum using the MD5 checksum of the user password + the random string + the temporary user_id as inputs. This string will then be used to create a URL with a unique POST variable and using the user_id as a prefix. Something like www.myurl.com/register.php?reg=[user_id][checksum]
Once the user clicks on the URL, the database finds the record with the user_id passed to it, then re-generates the checksum using the same inputs it has stored in the record and compares it to the checksum passed in the URL. If it passes, i move the temporary record to the permanent user table, delete the record and voila! (???)
Here are a couple examples demonstrating the basics of what you want to do.
A, and B.
Neither of these store the date for cleanup purposes, so you'd have to add that. I don't know that I'd take that tack, personally. I'd probably add an admin screen that listed unauthenticated users, where an admin could either delete or remind them.
posted by chazlarson at 9:33 AM on May 30, 2012
A, and B.
Neither of these store the date for cleanup purposes, so you'd have to add that. I don't know that I'd take that tack, personally. I'd probably add an admin screen that listed unauthenticated users, where an admin could either delete or remind them.
posted by chazlarson at 9:33 AM on May 30, 2012
Sounds mostly reasonable to me. I second RustyBrooks that you shouldn't need to make a checksum out of the userid and password. You just need a long, unguessable, random token to associate with the user.
Also, I haven't seen a separate "on deck" table. Rather, it's just an extra two columns in the users table: the random token, and a "confirmed on" date or "is confirmed" boolean or something. The advantages of this are that if a user, say, changes their email address, which you'll want to reconfirm, you just reset those two fields rather than dealing with locking that user and spinning up an on-deck one, and then re-activating that original user. If you really want to get rid of users who haven't confirmed their email, you can periodically delete the rows that are still unconfirmed after some number of days.
Lastly, and not asked but very important: don't store the password in the database! Always store the hash of it (preferably bcrypt) instead.
posted by losvedir at 10:52 AM on May 30, 2012
Also, I haven't seen a separate "on deck" table. Rather, it's just an extra two columns in the users table: the random token, and a "confirmed on" date or "is confirmed" boolean or something. The advantages of this are that if a user, say, changes their email address, which you'll want to reconfirm, you just reset those two fields rather than dealing with locking that user and spinning up an on-deck one, and then re-activating that original user. If you really want to get rid of users who haven't confirmed their email, you can periodically delete the rows that are still unconfirmed after some number of days.
Lastly, and not asked but very important: don't store the password in the database! Always store the hash of it (preferably bcrypt) instead.
posted by losvedir at 10:52 AM on May 30, 2012
Is there a reason you're re-inventing the wheel here? Account creation and management is built into a ton of well-used platforms like Drupal and WordPress as well as any number of plugins and the like for frameworks like CodeIgniter.
If you're moving forward with this I'd use this methodology:
User provides you information, you create a user records flagged to inactive.
In another table you create a record with the user's email address, a large random number/string, and a timestamp.
You email the address of records a clickable url that passes that long number back to you. The url should be on the other side of a signin requirement. When checking the passed-back token you compare the timestamp and make sure it's not more than X minutes old, based on your pricklyness.
This accomplishes several things.
One, you don't create a token that is at all reproducible. Your combined MD5 sorta does that but all the stuff in it is unnecessary. You just need a number so large as to be unguessable so that they must have access to that email to know it.
Two, by requiring the login you keep someone from just randomly pounding on your verification link. If someone is going to try shenanigans on you, at least make them go through all the steps.
Three, the expiration time reduces the brute-force window.
Four, keeping the verification table separate from the user table means your validation routines never need to update that table (marginally reducing your risk of SQL injection or other privilege escalation nonsense)
I still think you should use some well-tested pre-existing stuff if you have a choice.
posted by phearlez at 11:57 AM on May 30, 2012
If you're moving forward with this I'd use this methodology:
User provides you information, you create a user records flagged to inactive.
In another table you create a record with the user's email address, a large random number/string, and a timestamp.
You email the address of records a clickable url that passes that long number back to you. The url should be on the other side of a signin requirement. When checking the passed-back token you compare the timestamp and make sure it's not more than X minutes old, based on your pricklyness.
This accomplishes several things.
One, you don't create a token that is at all reproducible. Your combined MD5 sorta does that but all the stuff in it is unnecessary. You just need a number so large as to be unguessable so that they must have access to that email to know it.
Two, by requiring the login you keep someone from just randomly pounding on your verification link. If someone is going to try shenanigans on you, at least make them go through all the steps.
Three, the expiration time reduces the brute-force window.
Four, keeping the verification table separate from the user table means your validation routines never need to update that table (marginally reducing your risk of SQL injection or other privilege escalation nonsense)
I still think you should use some well-tested pre-existing stuff if you have a choice.
posted by phearlez at 11:57 AM on May 30, 2012
I'd use one of the many tested, debugged solutions to this problem, like phearlez said.
In addition...cover all of this by forcing SSL, and sanitize the data before you stuff it in the database or you find all sorts of folks try usernames like "Robert'); DROP TABLE users;-- ?" and wonder why your site blows up on a daily basis.
posted by kjs3 at 1:42 PM on May 30, 2012 [1 favorite]
In addition...cover all of this by forcing SSL, and sanitize the data before you stuff it in the database or you find all sorts of folks try usernames like "Robert'); DROP TABLE users;-- ?" and wonder why your site blows up on a daily basis.
posted by kjs3 at 1:42 PM on May 30, 2012 [1 favorite]
Response by poster: Thanks all, your comments will be very helpful.
I've got three books on my desk right now: Zend framework, drupal and wordpress. All of which I know will make my life much much easier and none of which, between 3 kids, a 45 hour a week job and a carpentry hobby, I have had even a second to read. I've gotta get this thing done by the weekend so at this point, it would probably take me as long to tinker with the ready-made code and integrate it into my friend's site than it would to just do it myself since i already know how to do the programming and the form and the processing is already built. But point taken of course, and quite correct under normal circumstances.
This is a project that i'm hoping will take off so that I can quit my full time job one day, but I doubt it. A little extra cash would be nice though :) Fingers crossed.
posted by postergeist at 1:19 AM on May 31, 2012
I've got three books on my desk right now: Zend framework, drupal and wordpress. All of which I know will make my life much much easier and none of which, between 3 kids, a 45 hour a week job and a carpentry hobby, I have had even a second to read. I've gotta get this thing done by the weekend so at this point, it would probably take me as long to tinker with the ready-made code and integrate it into my friend's site than it would to just do it myself since i already know how to do the programming and the form and the processing is already built. But point taken of course, and quite correct under normal circumstances.
This is a project that i'm hoping will take off so that I can quit my full time job one day, but I doubt it. A little extra cash would be nice though :) Fingers crossed.
posted by postergeist at 1:19 AM on May 31, 2012
This thread is closed to new comments.
posted by RustyBrooks at 9:06 AM on May 30, 2012 [1 favorite]