"invite friends via email" feature...what security implications should i concerned about? - php

I'm adding a feature to my site to allow people to invite their friends. I was going to accept a commma-separated list and allow them to import their Gmail contacts.
My question is, how do i prevent someone from just posting a string of emails to my script and essentially A) overwhelming my mailserver or B) spamming a bunch of people. Obviously, captcha would help with this, but just curious if there's other ways to limit our risk...
Since the contacts/etc are all on the front end, there's no way to hash it using our sites encryption key...so my initial thought of hashing the emails before sending them to our "sender" script probably wont work...
Any advice, help or direction on this is much appreciated!

First and foremost: Don't use a generic sender script! Any script that takes recipients and a message body from an external request is a security issue. Security is hard and you will make mistakes, opening you up to spammer. Better create several scripts that are only capable of sending a specific e-mail. E.g. a contact-us script that is hardcoded or preconfigured to send e-mail only to you. A tell-a-friend script that has a hardcoded or preconfigured message template in it.
Next, you need to be very careful about putting anything supplied by your users into an e-mail header (this includes message subjects, from/reply-to addresses, etcetera). Of course, it's nice to set the reply-to automatically to the user's e-mail address, but what if I type this as my e-mail address:
me#example.org\nBCC:spam-target#example.org
Now I'm spamming other people through your contact form, even though that form is only supposed to send mail to you.
You should treat anything that a user can put in a mail header (or message) as suspicious as you'd treat anything that goes in an SQL query.

Related

PHP/MYSQL email message board logic and security

I want to run this by the group to get some ideas on how to improve security.
Long story short, I have a web app that when you send an email to xxx#mydomain.com, using php and imap, the script checks the email account and then saves that email into mysql to be used for other parts of the application. We take all necessary steps to properly sanitize the data to prevent mysql injections etc.
However, In order for the incoming email to be saved into mysql, your email address has to be approved first as to not allow just anyone to have their email saved into our database.
My question is, if a hacker wanted to, they could mask the "from" email address of an approved user and if they found out our secret email address to send to, they could then have their messages saved to our database, bypassing our security measures. Is there any way to prevent this?
For instance, let's say that an approved email is safe#approved.com. Is there a way to check with PHP if that the email sent to our mail server actually came from safe#approved.com or was it masked?
I have looked at gethostbyname() , but not exactly sure how to implement it while not creating a bunch of headaches for our legit users.
Any ideas would be much appreciated, thanks!
There is no simple way to verify that a From: header is legitimate. There are methods that can help increase confidence in it, though:
SPF records can be used to check that the originating server is authorized to send for that domain, though this won't help with the "local-part", or the individual sending.
DKIM signing can indicate that the actual address used is authorized by that server, something often included by default on most email platforms (e.g. Gmail).
Unless you do additional work to verify these headers you've got no way of knowing.
If you're expecting email from an unsigned source, with no SPF records, it's anyone's guess as to if that's legitimate or not.
This is why you'll often see services with a "mail in" end point use obfuscated delivery addresses, that is a secret address of sorts that can be used to communicate with the app or service. For example, Evernote uses this approach, giving a unique destination email for each user.
This provides at least a layer of security in that unless that address is leaked out, it's highly unlikely that some attacker could exploit that address. Anything sent there is probably from the authorized individual.

filter_var W/ FILTER_VALIDATE_EMAIL vs custom REGEX

I've searched this site for similar answers and I still can't make up my mind. Also I'm new to this site.
I'm in the process of developing a PHP script to allow users to register. After they register they are sent a email with a token to validate that they have access to that email saying it is valid and it will mark them as 'valid users' otherwise it will delete that entry after a set time. What I'm wondering is if a custom REGEX that I made (which works fairly good for the most part just needs tuning every now and then) or if filter_var with FILTER_VALIDATE_EMAIL is better than my custom REGEX. I know that if you send too many emails that bounce back you might be marked as a spammer site and my client wouldn't like that too much.
Anything else that might help would be great help to me.
I would use Filter_validte_email if you don't have a lot of experience validating email or writing regex. It is also important to remember that any regex or filter will not prevent emails that bounce back, they will only check to make sure the entered address looks like it should. Thus you will get a valid check on noaddress#nodomain.tld even though this clearly will not be delivered unless nodomain.tld happens to exist and there happens to be a user noaddress with a mail account there.
See How to check if an email address exists without sending an email?

Is email verification with a link a bad idea

In my registration process, the user registers, they get emailed a verification link, and if they click it, only then would their account be verified. But isn't this verification method too easy for the bots?
I think an email could be created by a bot, but for sure if the verification is just clicking a link, it could also be automated by a bot. I'm not sure since I haven't done this and don't care to test it just to know, but my question is isn't this verification method flawed?
I'm thinking about sending the verification code to the user as a text which they would have to copy/paste manually into a form AND the form is captcha protected. Is this a better idea? any flaws with it?
Most of the suggestions are about verifying emails and using CAPTCHAs which of course you should do, but keep in mind that none of these methods is completely bulletproof.
Email verification
A bot can easily "click" on links in any email. Copying and pasting something would be slightly more annoying for the bot author but not much. Generally email verification is just that - email verification.
You verify if the email is likely to be controlled by whoever tries to register, but of course since email is usually sent in cleartext over untrusted TCP and relies on insecure DNS, then until we're all using DNSSEC and encrypt all traffic it will be easy to sniff emails and spoof servers and clients. The important thing to realize is that using email verification you get only a certain degree of confidence that whoever or whatever you are talking to is really a user of that email address.
Turing test
Answering a question that only human should know the answer to would be still more annoying but considering that you probably wouldn't have an infinite number of questions, the bot author might redirect unknown question to a real human and use cached answers if any question repeats more than once. Answering a question like "what is 12+8" like I've seen in some websites lately as a Turing test is completely counterproductive since this question is actually easier for bots than for humans. Probably the most popular Turing test for that are CAPTCHAs but here you also have to realize that they can be fooled.
First of all people are showing methods of circumventing CAPTCHAs, for example see the Decoding reCAPTCHA talk from DEFCON 18. Many CAPTCHAs are much easier for robots to decipher since they are generated by algorithms that are trivial to reverse. The reCAPTCHA distortions are also pretty simple but the words that they use are real scanned words that was hard for OCRs so in principle it should be much harder for bots, but it is not always the case.
And there is also a possibility to display captchas that you want to guess on other websites and have people answer it for you. Also there is a black market of people actually solving captchas so if your bot author doesn't mind paying something like two cents for a dozen then no matter how hard it is for humans, actual humans will solve it anyway.
Bottom line
The bottom line is that using any of the bot-stopping techniques will always be a compromise of how much would a bot owner (a spammer or anyone else who wants to register a lot of users in your system) be willing to spend time, effort and money to do it, and how much inconvenience for your users are you going to tolerate, because ultimately you will never be able to do any automated test to tell humans and bots apart without actually annoying humans and alienating people with disabilities (has anyone ever tried to guess the audio version of reCAPTCHA?), and still your bots may actually be human-powered, so not really bots but cyborgs, so to speak.
It's an arms race for which your honest users are paying a price. Please keep all of that in mind.
The questions is what are you trying to verify? When you send a link to an email address, what you can know is that whoever registered that account has access to the email address. It doesn't tell you anything about them other than that.
So yeah, bots can create an account, and use it for registration. If you want to stop bots, then yeah, a captcha is what you need to add. Note that there's little point in adding the code to copy/paste - that's both easy for a bot to do, and also doesn't gain you anything over the captcha.
As always, security and convenience are generally competing with each other.
A link in an email simply validates that it is an active email address. Yes, it's easy for the bots to handle this. But is your service so valuable that bots will be attacking it?
A CAPTCHA is always the way to go to ensure your users are human. The additional coding and frustrations involved with it are a trade-off.
In the end, keep things as simple as possible, but not simpler.
As pointed out already, you simply have some CAPTCHA validation.
My suggestion is though do human validation before your app creates the user account and sends the verification email. Added value of your site can't easily be forced to just spam verification emails and create bogus waiting to be verified accounts.
Nothing wrong with a link if you do that.
Yes, bots can enter emails and check the responses. I've also heard of endeavors toward bots getting better at image recognition and answering captchas, although I can't say for sure how good they are. If you are really really concerned, I would go with:
Email verification
Captcha
Simple random questions (How many ears/fingers do most humans have?)
Cell phone number that sends a code via SMS
The last one might prove to be the best in eliminating bots, but it will also limit who signs up for your website. Also, the more validations you have, the more you'll annoy users and the more you'll increase the barriers to getting them to sign up, which could also be a pretty big drawback. Personally, I think captchas are a good balance of bot protection vs. user inconvenience.
Are you verifying an email only or doing a full registration?
I always verify the email account first. then once verified complete the registration process.
so add a captcha at the verify email step.
In other words, ask the user to enter their email address, enter the captcha and submit the form.
That way only real people get the verification email sent.
It doesn't prevent human bots of course.
DC
It also means you don't need to store failed/bad registration data.
One problem is a user validating with one email address and then changing it during the registration process, I handle that this way..
When a user submits their email address the data is not stored at all. Instead I use $validation_code = md5(trim($email)+$secret) to generate the verification code. That way they can't change the email address on the actual registration form. The email and verification code is carried as a hidden field to the end to validate the email address. if the email address is altered from the verified one, registration will fail as the md5 no longer matches.
DC
I ran into similar problems with verification emails and testing. If you want to end-to-end test email verification try EmailE2E.com — it's free.
You can send and receive emails from randomly generated inboxes via an API.
It's perfect for testing Firebase, Amazon Cognito, or other OAuth providers that use email verification codes during sign up. Plus it has clients in Java and JS.

Activation on site

I have been running my website for a few months now and occasionally I find my activation isnt great. After the user signs up, they will receive an email which has an activation link provided.
I have a few problems and want to improve this if possible.
Firstly, the email sometimes doesnt arrive? Any reason for this?
How can I stop it going into the junk mail?
Secondly, at the moment, the activation is their username and an md5 of their username.
Is there a better way to do activations?
I'm always looking to improve and find better ways of doing things!
Thanks for your time.
Email doesn't arrive
First at all, you cannot really rely on mail. Never. Because you can't even know if it was received or read. A mail may be blocked as spam on server side, can be filtered on client side, or can just be lost or ignored.
There may be plenty of causes. For example, you may use e-mail authentication mechanisms. You may also start to check if there is reverse DNS for your domain.
Further, you may want to read some documentation and books to know how spam filters work. It will show you some obvious methods to reduce filtering of your mails, like sending mails in plain text instead of full-HTML, but also less obvious stuff like the words to use, etc.
If you have no choice and you must send mail, probably the most easy solution to prevent spam filtering would be to ask the users to add your domain to the list of safe senders. In practice, nobody will do it for you.
Activation through MD5
There is obviously a better way, since the one you implemented does not provide anything. If the activation is a hash from user name, you can as well just tell the users to calculate the hash themselves (thus avoiding all the problems with mails filtered as spam).
Normally, the users may not know what their activation code would be. It means that the activation code must be random or difficult to guess.
Generate a set of random characters, save them to database and send the code by mail. Then you would just need to validate the code against the one you keep in your database.
Some emails will always end up in the trash folder. It's probably best to put up a notice so that people know to check there, and make it possible for the user to re-request the activation email.
Using the MD5 hash of the username is not a very good idea because anyone can automate that. At the very least add some salt before hashing it, or even better, use a completely unrelated random token saved in your database.
For your second question, you may want to generate a random activation code and store it in a database. When the user clicks the activation link you could verify the code in the database using their e-mail address. This way a malicious user will have a more difficult time automating registration on your site.
$code = md5(uniqid(rand(), true));
If you're on a shared server, services like Yahoo are apt to label you spam. They want you to have a dedicated IP. It's almost impossible to get users to check the 1000 messages in their spam folders for your one activation message.
The MD5 hash is fine if you're hashing with a timestamp.
Keep this implementation, but supplement it with OpenID. That will take care of your Gmail and Yahoo users.
Yes, that's wrong. You shouldn't use MD5 for that.
The most popular way of do it is generating a rand code and saving it in the users table in the DB and send it by email as a GET parameter of the link.
About the emails, I would tell users to look in theit junk folders.
First problem: Make sure your mail isn't spammy. Follow the default guidelines for setting up mail... things like making sure you've got your SPF records configured, your mail is well-formatted, doesn't include spammy words. I generally test against Gmail, Hotmail and a server running SpamAssassin to check mails I send out; examine the headers to see if you're triggering any serious anti-spam rules.
Second problem: You'll want to make sure that the user cannot guess what his activation key is (thus removing the need for receiving the email). An MD5 of the username is insufficient for this. However, if you salt the MD5 you can easily prevent people from generating the MD5's in an automated way (that's an open invitation for automated signups). Adding Salt refers to adding a large amount of pregenerated random data to your input before hashing it. That way, the attacker can't lookup the hash in a 'rainbow table', as he no longer knows what the input for your hash was. Of course, you could just as well use a randomly generated string, which would probably be easier.
Another look on user registration. Let yourself inspire at stackoverflow and use OpenId and you don't have to care about user registration.
Update
You don't need to validate OpenId user via email. A user which signed up via Google or MyOpenId account is valid.
You don't have to care about questions if user is a bot? This servers did it already.
I have never got verification email from stackoverflow.
Mail arriving in the junk folder is a perpetual problem. The range of 'not looking like spam' strategies are numerous. Beyond the Junk folder I think that the overwhelming majority of reported 'not received' situations are actually just delays in propagating the email.
I'm currently implementing a resend for the activation email confirmation despite the fact that it should only actually be necessary in cases where the user has accidentally deleted the email and purged their trash or a transient error has discarded the mail. These cases are going to be rare but do exist so needed to be coded for.
I think the most important reason for implementing the resend of the activation confirm is customer service. It provides the user with an action that they can take while waiting for their mail and in the course of doing so and re-checking their email the activation email will eventually appear.
I wouldn't use the md5 as it creates too predictable a result. You want something that has a random or at least less predictable element. It is then problematic if you are invalidating the hash/token in the original email by resending a new mail so I would avoid overwriting the existing token and would instead re-use the same token which you should have stored or better stored the values from which it can be validated. This does constrain how you create the token as you want to be able to recreate it in the later resend mails or at least to be able to continue to validate all the inflight mails as valid. I am using a session aging model to resend the same token if that token is still valid. There is no reason why the user shouldn't see it as the same token and hence understand that they are all valid. In the case of an expired session/token a new one needs to be generated.
It's good practice to expire the activation mail token in case the mailbox falls into the wrong hands weeks or months later and the old mail is found. Assuming this can have some undesirable effect on the state of the users account at that later point.

are these attempted injections on my contact form?

I have a PHP contact form mailer on my website. The contents don't store in a database, but are emailed directly to me. I have received a couple strange contacts in the last few days.
The user has to fill in name, email, confirm email subject and message.
I have a javascript security in place that verifies an email is typed in the same twice, and checks for the # and the dot. Also, required fields are checked with javascript.
Here is the most recent message-you can see it is a bunch of bogus links, etc. Is this anything I should be concerned of from a security standpoint?
Name: fvjnqazcy
Email: cervau#fbcalj.com
Email confirm: cervau#fbcalj.com
Phone: 47668113220
Subject: uSMvoegKPt
Message: KU17Gd lsyixbpcjddi,
[url=http://sojlxycrnxlb.com/]sojlxycrnxlb[/url], [link=http://wesixtcvuzbj.com/]wesixtcvuzbj[/link], http://dcgfyjhpfpbx.com/
It looks more like a spammer to me. If you have more of these messages than you can handle, you need to add a CAPTCHA to your contact form. I don't think it's intended to exploit a potential security issue in your application though.
Yeah, I agree with Mehrdad, it just looks like a random spam bot. Don't ask why they are doing that; I don't think there is a real reasoning for them to add spam..
I have a javascript security in place that verifies an email is typed in the same twice, and checks for the # and the dot. Also, required fields are checked with javascript.
You really shouldn't do any important checks with JavaScript. Or at least not without testing them on the server side as well.
JavaScript is easily disabled and then all your checks will fail. Especially bots never interpret JavaScript, so all your checks won't be made and all input is just accepted as it is.
To prevent spam in general you should gradually add more security checks on the server side. One rather hard option is adding a CAPTCHA, but moving those checks to your server first will probably help as well (given that the bot enters two different email addresses).

Categories