I would like to have a aspect of my site that users can use to sign up for a newsletter.
I am not 100% what the best way to accomplish this task would be.
What I can think of is very simple:
One input with a submit button, the user enters their email address there.
A random 32 character hash is generated and stored along with their addess within a mysql table.
Am email is sent to the address containing the hash and asking the user to enter their email address and the hash on a page that checks it against the mysql table.
If correct the email becomes active by defining an additional entry on the table.
That is about as far as my knowledge of the two can take me...
What i would like to accomplish, is in the confirmation send the user a link that they can click to confirm their address... something like http://www.mysite.com/users/newsletter/?user=aGuy&confirm=blahBlah.
But I really do not know where to start with something like that... And as i understand it, allowing mysql queries in such a manner is not secure...
Would someone be able to provide me with some more information regarding this matter?
This being in the form of suggestions or links to tutorials that may cover something like this.
Thank you for taking the time to read this!!
You're close.
When a user submits his email address, insert it into the database. At a minimum, the table should 4 fields (id,email,verified,key). The id is just a surrogate key (auto-increment). verified should default to false, and the key shouldn't really be a hash but a randomly generated string -- anything that's hard to guess. Hashes are deterministic, so hashing the user's email address with an md5 wouldn't make for a good key if someone figured out what algorithm you were using. A random element is better suited, but again, anything hard to guess will serve just fine.
The email should contain a link that holds the id and the key. You use the id to look up the record in the DB (since it's unique) and then check that the key in the URL matches the one stored in the database (key doesn't have to be unique). If they match, set verified to true, and voila.
For bonus points, you can store a date that the verify email is sent, and you can prune out unverified emails after 24 hours or so.
Your description of the flow is fine, just start implementing it.
The sfGuard package implements a similar flow, check out their source code and database design.
Related
I'm adding an option for my users to change their email, and I'm thinking what is the best way of doing it in a safe and fool-proof manner.. so far I have the following options
1) When user changes the email, system stores in a temporary column in the database and sends an email to the new one, requiring the user to click the link to confirm it and only then, change it (I would need 2 extra fields on my DB - temp_email and email_token)
2) When user changes the email, system would gather data from AccountID and New Email, encrypt it and send it to the new email.. when the user clicks the link, system decrypts it and changes accordingly.
I really like the second option, since it does not require saving extra fields on the database.. so my question is.. which one is a better solution? Or perhaps a third one..
I have two fields in my users table: recovery_hash and recovery_time that are updated when a user changes something. I put in a random hash and the current time.
I then send an email to that person (in your case, to their new address), and in the link is the hash (http://foobar.com/verify/randomHashG03sHere). The user clicks the link and it goes to a verify script on the server - which validates the hash and then checks to see if the current time is within an hour of the recovery_time. If both checks validate, I make the change, which, in your case would be updating the users email field with their new email address - which you could store in a separate table, or even in the same users table as a new_email field.
Since you're anticipating the user wanting to change things, you could just store the new email address in a separate table, such as users_temp.email and then update the users table with that new value after it's been validated.
You could just create another table to deal with temporary e-mail addresses (e-mail + AccountID + token + timestamp (possibly)).
I would highly avoid option 2. Keep all your data local on your server! In case someone breaks your encryption he can mess up your entire database or webservice. Especially credentials or email-addresses should never be outsourced. Option 1 is much more recommended, though the data could also be stored in a different manner.
I want to implement user mentions with #username like in Twitter. But, in my app, the username may change. My approach is to parse the post before saving into the database and convert all the #username to #userId. What do you think of this? Does anyone has any better alternative?
Store the original text, as is, and create a table of related records with the uid and username.
Example schema:
post [table]
id
text
user_mention [table]
id
post_id
user_id_mentioned
user_name_mentioned
When a post is saved, your code should go through and create all the user_mention records. You can loop through the mention table to send e-mails or whatever else you want to do.
If the user changes their user name, you now have the option of updating the post with the new username, or having the old username link to the correct user.
My rule is to never, ever modify original unstructured text before saving to the database (but do sanity check it to avoid injections and whatnot) and modify the data only on output. This means you always have the user entered data, and you never know when that will be valuable.
Maybe one day you are interested in who changed their username after being mentioned n number of times? Or some other report that you can't get because you modified unstructured data. You never know when you will want the original data and, in this case, you get the added bonus of having your text easier to work with.
Yeah, I think checking the username list at the post time, and converting them internally to a user ID makes sense. Then, whenever you display the post, translate the user ID back to the current username.
Note that this will be more difficult for non-dynamic content, such as emails sent, etc.
Also, I'd make sure that the usernames are displayed in a way that makes it clear that they're not words the OP posted, otherwise, that would give a way for users to inject text into someone else's post.
Yes I think that is good. Twitter itself doesn't just use Usernames it uses UserIDs.
It gets the tweeters user ID then looks it up to get the the actual username.
Documentation : Mentions and Lookup
Each user should have a unique ID. You should match the ID's with the username before you send it anywhere which would be visible for users.
I have a site where users must confirm their e-mail using a typical e-mail confirmation script with a specific (but long) Confirmation Link for each user that includes the usual hash parameter.
The problem I'm having is that some users are having problems with the long and complicated Confirmation Link due to the device they are using.
So I need to create an alternative way to generate the unique Confirmation Link for each user such that no pattern is obvious so that it cannot be figured out and abused.
I've been looking at Base62 encoding and decoding, but the one I found is based on numbers only, which would limit me to using the sequential unique User ID's, which then creates an obvious sequential pattern in the encoded results which could easily be abused.
Preferably, I want a solution that will not require me to alter the DB.
Ideally, I would like to basically create a shortened URL similar to how Bit.ly and other url shorteners create their unique URL's, but that can be encoded and decoded either off of the User ID, username, or e-mail, and preferably have the encoding/decoding "salted" with a unique key so that no pattern emerges in the encoded results.
EXAMPLE:
So instead of the confirmation link looking like:
http://domain.com/confirm?email=blah#blah.com&hash=1f3870be274f6c49b3e31a0c6728957f
I would like it to look like:
http://domain.com/confirm/Sg5rdn
Where I would then simply decode Sg5rdn to get the Username, User ID, or E-mail of the user and confirm them.
Is this even possible?
Instead, just create a table with confirmation codes. When a user should do a confirmation, create an unique code (using base62 or whatever), insert it into that table and assign it to the user id.
Then, when the user hits the confirmation link, just fetch the user id etc from the confirmation code table (and check that the code exists and still isn't confirmed etc).
I would suggest you store the code in a column in the user table:
example table very shortened:
id--user---email--------------key-----confirmed----other stuff
1 bob bob#example.com 1h323f 1 ...
2 rob rob#example.com 18gg3f 0 ...
3 steve steve#example.com a862gf 1 ...
4 tom tom#example.com 17g23f 0 ...
As the user signs up for an account pre create the key and store it along with the username ect
Then when the link is clicked check for the key against the email, then update the confirmed to 1.
You could use .htaccess on the link to make it even shorter:
RewriteRule ^confirm/(.*)/([a-zA-Z0-9]+)$ confirm.php?email=$1&hash=$2 [L]
eg:http://domain.com/confirm/tom#example.com/17g23f
Hope this helps
I'm afraid your expectations a bit exaggerated.
The only thing you can really do is to shorten a hash a little.
the only way to "decode" Username, User ID and E-mail out of Sg5rdn is to fetch them all from the database.
Ive been asking around for some feedback on my website and one comment I received was the following
"I signed up with email#email.com and managed to active my account with http://www.mysite.co.uk/activateuser.php?email=email#email.com
You need checksums to stop it."
Can anybody elaborate on this and how I can implement them into my activation?
In theory, If I was to create a row named "rand_key" in my DB and when a user registers a random key is stored in the column, could I then use this as the activation as opposed to the email? thus making it un guessable?
You need to create a unique user key, which shouldn't be related to user data. Usually you could do something like hashing the output of a random generator function in order to make it unique and use that. Then you point them to the link:
http://www.mysite.co.uk/activateuser.php?userid=generated-unique-hashed-key
This unique user key should be added as an extra field to the table where you store your user info, or related to the user in some other way. By keeping the key unrelated to user data you make sure nobody can discover a user's key and maliciously activate/do another action instead of your user.
Then you should test the user key on arrival for some conditions:
not authorized yet - authorize
authorized already - some error
wrong key - some error
Also, there should be an expiration date associated with your user, upon which you just deactivate the user along with his key.
The person means you can activate your address by going to that url and simply putting the email address in thr url. You could do this without actually getting the activation email.
By using a checksum, you force thr user to click the link. E.g.
Activate.php?email=aaa#bbb.com&check=A1234b23
At the time of sending the email you would geneate a random code. Store this in your database somewhere. Append it to the url the user is given. When the user clicks the link, you check that the code matches the code stored for that email address. If it matches, validate the email. Else do not.
In theory, If I was to create a row
named "rand_key" in my DB and when a
user registers a random key is stored
in the column, could I then use this
as the activation as opposed to the
email? thus making it un guessable?
Yes. Keep in mind that you don't necessarily want random as much as you want unique (in order to avoid two email addresses accidentally getting the same activation code).
You could do something like:
$key = mt_rand().'-'.uniqid('', true);
echo 'http://mysite.com/activate?key='.urlencode(base64_encode($key));
That would be tough to guess and would be guaranteed unique.
Working on a web based "buying and selling" application with PHP MySQL where users can post adverts for items and services.
Before a new advert is displayed on the system there must be a method of verification to ensure that the user provided email address is correct, and that the advert is legitimate.
I want to send the creator of any new advert an email containing an url which directs to a page whose primary functionality is to receive a posted variable, $advert_id, and to select the advert from the db for updating / editing / deleting.
This variable is embedded in the url with PHP syntax
ie. [http://www.example.com?content=modify_advert&advert_id=2246317].
This part is quite simple to implement, BUT, if a user was to modify this variable called "advert_id=2246317" to any other integer, they can access other posts/adverts in the system.
The system is advert based, and users dont need an account or login to post, so we cannot prompt for a login at the point of verification which would have been convenient.
Any ideas as to how we could protect the adverts/posts in the system from being accessed via the aforementioned url???
Any suggestions?
If visitors will only be viewing that page from the link you send via e-mail, you can include a hash in that address instead of the advert_id — essentially a random, one-time password.
One common and "often good enough" trick for generating such a random password is to take a single, secret, truly random string (I usually use grc.com), concatenate it with the unique advert_id, and hash the whole thing with, say, SHA1(). Like so:
UPDATE advert SET advert_hash = SHA1(CONCAT(advert_id, 'lots-of-randomness-here'))
You could even vary this by adding time(), or (better still) a random number to the end. The outcome is a 40-character string stored in your database that nobody could possibly predict (without knowing the secret data you used to generate it).
For example, I might get this instead of advert_id=1:
f2db832ddfb149522442c156dadab50307f12b62
If I wanted to sneakily edit advert_id=2 (which somebody else created), I'd first have to guess that the hash is this completely different string:
e5c6a3a9473b814b3230ee7923cbe679fcebc922
So, include that in the URL instead of the advert_id (or, if you like, in addition to the advert_id), and suddenly your users are powerless to ruin other people's content.
You could add a salt to the id and then hash it.
sha1($advert_id . $salt);
Send this to the user in the URL instead of the advert_id, and store it in your database, along with the advert_id.
Then when they click the link, you find the matching advert for that hashed value.
Making the salt a secret is how you keep users from 'guessing' a valid URL that will let them modify an ad that they did not post. Perhaps you could use the users email address, the time posted and/or a name or something that the user enters when they make a post.
Generate a GUID as the advert ID so simple ID guessing attacks are unlikely to succeed.