I'm trying to safely store email addresses in a database, but need to check if a specific email address is already in that database. My current encrypting with openssl_encrypt (I used the example on https://www.php.net/manual/en/function.openssl-encrypt.php) will output a different output every time I refresh the page. That way I cannot check if the given email address (stored as encrypted string in the database) is already in that database; I don't want to decrypt them all and use a foreach loop to check existence.
Is there a secure way of storing the email addresses, but where I'm able to quickly check the existance? Thanks!
Edit:
I think a bit more context is needed. I added the underneath additionaly:
MD5 is not secure for a while now. If my database is hacked, I don't want those email addresses saved in a unsecure hash method.
The application is to register yourself when a product is not in stock. When the product is back in stock, all the registered persons should receive an email. So I do need to decrypt the email addresses again to send the email to.
Now the issue is that when a person is already registered, I want to prevent registering twice and give feedback that they already registered. To prevent decrypting all registered email addresses and then check if one of those is trying to register, I want to do something like "select * from table where emailhashed = 'HashedEmail'". With openssl-encrypt I get different HashedEmail outputs so that doesn't work. The result will be zero and the registering continues resulting in a duplicate (triple, etcetera) registration.
Related
I'm not familiar with PHP / MySQL and Emails. And I'm pretty sure this question has been asked somewhere already, but I cannot find it. So I apologise if this is troubling and thank you in advance!
Is it possible to do something that user has to click on a link in email first before the user is added into database???
And you know how, for some websites, they have a unique web address for each email validation (Shown in red on the picture)? How do they create a webpage that's unique in for every email ?
Picture credited: https://kayako.atlassian.net/wiki/download/attachments/5734920/subs-validation.png?version=1&modificationDate=1291956283000&api=v2
Thank you a lot for the attention! If it's possible, I prefer not having straight scripts that I can copy and paste because I like to find out myself :P But please do give me some hints because I'm totally lost.
If there's anything that's not clear, please tell me, I'll try my best to clarify it!
The Registration process
User fills out a form online with basic details including an email and password, and submits the form to register.php
register.php adds user info to a temporary location, such as a pending_users table which has all the fields the user submitted along with an expiration and an activation_code fields. This code can be any random, impossible to guess value. eg: hash('sha1', mt_rand(10000,99999).md_rand(10000,99999)). Just don't do anything predictable such as hash the current time, or the username
register.php sends an email to the user with a URL that will link to activate.php and that includes the activation code. eg: example.com/activate.php?code=a2ef24... The email should also inform the user of the expiration (1 to 12hrs validity seems ok to me)
When user clicks the link, she triggers a GET request to activate.php. In doing so, the user proves ownership of the email address
activate.php gets the code from the request parameters, eg: $code=$_GET['code']. With that code, the script queries the pending_users table for the record matching that code.
If the code is found, check that it hasn't expired before proceeding. Expiration prevents someone else much later who gets in the user's account from completing the registration.
If the code is valid, capture the user details from the matching record and delete that record from pending_users table.
Write a matching record in the regular users table. Until this is done, the user could not log in because login script only checks the users table, and ignores the pending_users table.
Registration complete.
Security Note I:
For your users' protection, never store passwords in cleartext. When you receive it from the registration form (eg: $_POST['pwd'], do:
$pwd = $_POST['pwd'];
//first validate; it should meet minimum requirements
$pwd_hash = password_hash($pwd, PASSWORD_DEFAULT); // <- the hash gets stored
Later, to verify the password, do:
password_verify($cleartext_pwd, $pwd_hash);
It will return true if the password is correct; false otherwise.
Security Note II:
For your protection, never insert user supplied values directly in your DB queries. This means any value that arrives from the outside. Not just usernames, emails, passwords... but also values that you're getting back from the user such as activation_code above or cookie values or headers (eg User-Agent). Instead, learn to use prepared statements. This will protect you from SQL injection.
Not sure if it's possible to add datas in database after the validation...
When I want to do something like that, I create a data in the users table (or metas users table) like "validate".
If this data is "true", then the user already did the validation and he can use his account. If it's still set on "false", the user didn't validate his account : he can't use it.
With that, you have to make sure the account is validate when the user tries to log in, but it's not a big deal ^^
Hope it's usefull.
Those are not a unique websites, there is only one script validating the registration finalization. The incoming requests (when the user has clicked the link) are routed all to the same script by means of server side "request rewriting", so that the random token value is available as an argument (parameter) to the script execution.
What the script does: it checks if that random token value does exist in the database where it has been generated and stored before when the user actually registered.
The only thing left to do for that script is to remove the confirmation random token and/or set a flag indicating that the registered use has actually confirmed his identify (email address) by clicking the link.
Easy and straight forward. Hard to bypass, since you cannot guess what random token value has been generated for what registered user without receiving the email. However take into consideration that it is trivial for an attacking script to use anonymous email services (one time email addresses) to receive and evaluate such a confirmation request, if the process is known to the attacker.
I'm designing a user registration form and am working on sending a confirmation e-mail. The script that is responsible for adding the username/password/e-mail address etc. to the database is getting rather long and I wanted to break the code responsible for e-mails into another file. I was thinking about how the two scripts would work together; would the database script include the e-mail script or redirect to it and pass the arguments. Or do I have it backwards? Would it be the e-mail script including/calling the database script?
What happens first? Does 1) an e-mail containing an account activation link get sent out before any data is added to the database or 2)is the data put in the database right away with an "activated" field set to false and when the user clicks on the link in the e-mail the field will be updated to true 3)or some other way?
#2, this is so that other users don't take the username twice. If you don't save the information instantly, then other users can also activate their account and you'll have errors with that.
Most websites have an expire on their activation so that the usernames can't be held for a long period of time.
A column for state such as user/banned/confirmed/unactivated would be necessary to keep track of who has activated and who has not. A cron job could be used to sweep the database for old inactive users, basing on the timestamp of registration.
Every system I've worked with has just stored the user in the database until it's used, but when spam becomes an issue you can look at other answers.
You need to store the username and password somewhere and sending it in the email is going to cause issues, and otherwise the link you give the email won't know which user to activate, and doing wacky things like storing it in the session is going to cause many, many ux issues.
Other than creating a second table for un-activated accounts, and searching both for the two different calls you need to search both (creating new user/email, and changing username/email), I don't see a better solution.
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.
Say a user registers on a site with an email address that needs to be verified first before accepting the user's registration.
The general approach is to send an email to the email address provided. The user then checks his/her inbox and clicks a link that would tell the site that the email address is valid. Usually, the link would have some sort of code embedded in it that tells the site whether it's a legit validation of the email address.
My question is about the code. What's the best way to implement it? Some ideas:
A random string is generated when a new address is entered into the site. This random string is stored in the the DB and then emailed to the registrant. The link in the email will contain the random string as part of the URL.
The email addressed is hashed. This means nothing needs to be saved in the database because the application will know how to unhash this. (My concern with this approach is if the user later changes his email address to something he previously entered, the hash would be the same. Not sure if this poses some sort of security threat.)
Some other approach?
I'm looking for general advice to this problem.
Number one, the random string, is the safest (and AFAIK, the most common) way to go: It makes it completely impossible to maliciously do things to E-Mail addresses that I haven't received the E-Mail for.
Also, you can remove the random string after successful completion, making it clear that that particular address doesn't need activation any more.
i'm using 1st approach every time
Create a random code
Store it at DB
Mail it to user with clickable link like activation.php?key=blabla
At activation page let user able to enter it manually too
At submit compare the keys
Activate user
If user change mail adress return 1
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.