Complete protection against mail-injection - php

Suppose we're sending trivial feedback and going to make these fields dynamic:
sender name
sender e-mail
subject
message body
would be this PHP code enough to protect us from all kinds of mail-injections?
//sanitizing email address
if ($email = filter_var($_POST['email'], FILTER_VALIDATE_EMAIL)){
//encoding subj according to RFC and thus protecting it from all kinds of injections
$subject = "=?UTF-8?B?".base64_encode($_POST['subject'])."?=";
//encoding name for same reasons, and using sanitized email
$from = "From: =?UTF-8?B?".base64_encode($_POST['name'])."?= <$email>\r\n";
//protecting body as it mentioned in http://php.net/mail
$message = str_replace("\n.", "\n .", $_POST['text']);
mail('me#example.com',$subject,$message,$from);
}
at the moment I am playing with names like "some#email.com, other#email.com," but it seems that all available mail clients handling it correctly

would be this PHP code enough to protect us from all kinds of mail-injections?
It looks pretty comprehensive, just as long as your email client supports the RFC 2047 encoding method you're using in the headers. (Some webmail clients don't recognize the encoding.)
My only recommendation, other than not using mail() to begin with, would be considering is_email rather than the built-in filter. The built-in fails a number of edge cases.

It depends, if the filter complies with rfc that specify that the local part cant contain anything if it is surrounded by " or whatever character some address like "foo\r\nTo: poor-guy#dom.tld\r\nTo: dummy"#foo.tld will give you headers like :
Subject: foo
To: poor-guy#dom.tld
To: dummy"#foo.tld
quite bad ...

Related

Does the (message) parameter of the PHP mail() function need to be escaped? [duplicate]

I am feeling a bit awkward, because I am generating a mail-body with PHP without escaping the variables. In HTML I am using htmlspecialchars() or similar functions, for command lines escapeshellarg(), but for mails? For example something like this:
<?php
$usercontent = $_GET['usercontent'];
mail("dummy#nowhere.tld", "My Subject", "My body with $usercontent included");
?>
What could a possible attacker do with a script like the one above and how could I protect against such an attack? Or is PHP mail() save and why?
Update
Please refer to the example:
Only the body is affected (No Headers!)
Content-Type is text/plain
Some proof to the answer would be nice
MTA is a postfix sendmail with "/usr/sbin/sendmail -t -i"
The basic e-mail message body is plain text. If you want a different type like HTML or a multipart message, you need to use the MIME extension and specify the type accordingly using Content-Type (e.g. text/html for HTML or multipart/… for a multipart message).
So from the security perspective, there is no way to inject anything harmful (at least not as per specification). Even non-ASCII characters should be handled correctly despite the lacking declaration of the used character encoding.
However, there still may be some flaws in e-mail clients which can be exploited this way. But I doubt that.
Good question. I don't believe you need to escape the body text, but I do know it's possible to add headers to a mail (like a BCC to thousands of addresses) if you allow the user to input a from address. So if you put variables in that, definitely check for newlines (\n and \r) to make sure no additional headers are added.
Think of the body of the email this way: "Mission top secret destination unknown." We may not know what kind of client will read the message, but we can guess that we do not want live, user supplied, unescaped HTML to show up in it. Since many clients read mail in HTML, the best thing to do would be to htmlentities() the user supplied e-mail body.
A method from my escaper class.
<?php
class escaper
{
public function superHtmlEntities($string)
{
return htmlentities($string, ENT_QUOTES | ENT_HTML5, 'UTF-8', true);
}
}
?>
========================================
At minimum, consider something like this and more as you do your research.
<?php
$esc = new Escaper();
$usercontent = $_GET['usercontent'];
mail("dummy#nowhere.tld", "My Subject", $esc->superHtmlEntities("My body with $usercontent included"));
?>
It is not secured against XSS atack because if your mail contains HTML someone can inject it into mail.
The good behaviour is to check and valid data which you expect to have. If I were you I would escape this string. It costs almoust nothing and you don't have to worry about consequences of not using it.

Are to, subject and body safe against injection using mail()?

I have read the following comment in the official documentation of php about mail() function:
Although it is not documented, for the parameters $to and $subject the mail() function changes at least \r and \n to space. So these parameters are safe against injection of additional headers. But you might want to check $to for commas as these separate multiple addresses and you might not want to send to more than one recipient.
Is it correct? Also, I have always considered the $message parameter safe against injection, is it also correct?
I know how to protect myself against injection, I just want to know if I can avoid to filter those parameters.
Yes, that's true, but it's also incomplete. In the engine source code, the function php_mail_build_headers ensures headers comply with RFC 2822 § 3.6 requirements for maximum number of values. Particularly, the following headers are checked for single value:
orig-date
from
sender
reply-to
to
bcc
message-id
in-reply-to
subject
Yes, the message parameter is safe from header injection by definition: the message part is inserted after the separating new line between headers and body, so any header-like text inserted as part of the message will appear as literal text within the message body.
For your comment that you don't want to apply those filters.
I think you can get it done automatically by using Zend_Mail as I commented.
$ composer require zendframework/zend-mail
I'm pasting this from their documentation:
use Zend\Mail\Message;
use Zend\Mail\Transport\Sendmail as SendmailTransport;
$message = new Message();
$message->addTo('matthew#example.org');
$message->addFrom('ralph#example.org');
$message->setSubject('Greetings and Salutations!');
$message->setBody("Sorry, I'm going to be late today!");
$transport = new SendmailTransport();
$transport->send($message);

php mail() remove CC, BCC and security

I'm new to stackoverflow and couldn't find an answer to my question which is; How do I secure my mail() code in php to prevent people from adding bcc which would ultimatly result in mass mailing? My website uses the PHP mail() service to email me when a new comment has been entered in my site. What is the best way to prevent people tampering with it, such as removing the bcc? What I have so far is:
function mres($input){
if (get_magic_quotes_gpc()){
$input = stripslashes($input);
}
return mysql_real_escape_string($input);
}
$name = strip_tags(mres($_POST['name']));
$comment = strip_tags(mres($_POST['comment']));
$to = 'myself#gmail.com';
$subject = 'Website - comment';
$body = 'A new comment has been entered on the website.'."\n\n"."$name".' said: '."\n\n"."$comment";
mail($to,$subject,$body);
Assuming that this code is followed by:
mail($to, $subject, $body);
Then it's safe, if overkill -- the only arguments to mail() which are vulnerable to injection are the ones that control header fields ($to, $subject, and $additional_headers). strip_tags and mysql_real_escape_string are both unnecessary, and the latter will make apostrophes show up as \' in your email.
If there's no following call to mail(), then it's trivially safe, because it doesn't do anything. :)
I would look at something like http://mailgun.com/
As it is, your mail will often end up in people's spam if you just use mail()

Injection to the mail command when only $text is user input

Is there any security risk of injection in the following PHP script?
<?php
$empfaenger_1 = "test#example.com";
$sender = "test#example.com";
$name = $_POST['name'];
$telefon = $_POST['phone'];
$betreff = "Test";
$text =
"Please contact me
Name: $name
Telefon: $telefon";
mail($empfaenger_1, $betreff, $text,"from:$sender");
$url = htmlspecialchars($_SERVER['HTTP_REFERER']);
echo "<center><br><br>Thank you<br><br>";
echo "<center><a href='$url'>Back</a>";
I think mail injections are only possible in header fields. Mail injections into body text are not know to me.
Anyway look out for XSS, you should use strip_tags():
$name = strip_tags($_POST['name']);
$telefon = strip_tags($_POST['phone']);
Injection in mail
Here the risk appears minimal. A couple of answers here point to the possibility of HTML injection into the email. For HTML emails, this is a possibility, but HTML mail messages will have the Content-type header set to text/html or as a part of a multipart message. RFC 1521 stipulates that a HTML content-type must be set explicitly, and that if no content type is specified that plain text is default:
Default RFC 822 messages are typed by this protocol as plain text in the US-ASCII character set, which can be explicitly specified as "Content-type: text/plain; charset=us-ascii". If no Content-Type is specified, this default is assumed.
In the above code, the user-provided text is inserted after the headers; an attacker would have no opportunity to change the content type (either to HTML or to multipart, the latter allowing injection of a MIME boundary).
The end result cannot be anything but a plain text message. If a user injects HTML tags into the message, the person reading the email would see those HTML tags in the message. Email clients generally don't opportunistically examine plaintext messages to locate and parse embedded HTML and JavaScript.
Injection elsewhere
While the use of mail is probably safe, there is a potential injection vulnerability in the remaining code:
$url = htmlspecialchars($_SERVER['HTTP_REFERER']);
echo "<center><a href='$url'>Back</a>";
By default, htmlspecialchars uses the ENT_COMPAT | ENT_HTML401 flags, which does not convert single quotes to '. The link href attribute is delimited with single quotes. So if an attacker can coerce the HTTP referrer to include a single quote, he/she can invoke a routine XSS attack. (for instance, if referrer is coerced into the equivalent of http://whatever/a' onclick='alert(), clicking the link can invoke arbitrary JavaScript. To resolve this, either place "$url" on the second line in double quotes, or call htmlspecialchars with the ENT_QUOTES flag.
There is possibility yes, one can inject javascript code for example if someone put this as their name:
<script type="text/javascript">
window.location = "http://www.google.com/"
</script>
Anyone viewing that name would be redirected to google.com; You can prevent this by saying:
$name = htmlentities(strip_tags($_POST['name']));
If the client that opens the email in html view mode, and the user injects script, then yes, it's vulnerable to XSS, and by extension, CSRF. You should, of course, sanitize all untrusted input.
More specific XSS protection information can be found at the OWASP web site.

Sending mail and validating an actual email?

I am sending users an activation link via php, I only have a regex in place to check if the email consists of *#*.* which is fine, but I would like to check if the email actually sends also.
I tried to do this with
if (mail(....)) {
// success
} else {
// error
}
But when I enter an email of a#a.a it still goes through to the success step.
How can I actually check if it is a correct email in php, thanks.
validate the email address preoperly with
if (filter_var($email_a, FILTER_VALIDATE_EMAIL)) {
echo "VALID";
}
the email server will return true on accepting the email it does not know if it will get to the user the only way to do this , and i'm sure you have seen it, is to get the recipient to click on a link in the email that sends them back to your site, then you know its valid\used address.
From the PHP docs
bool mail( string $to , string $subject , string $message [, string $additional_headers [, string $additional_parameters ]] )
Returns TRUE if the mail was successfully accepted for delivery, FALSE
otherwise.
It is important to note that just because the mail was accepted for
delivery, it does NOT mean the mail will actually reach the intended
destination.
Just because an email address is formatted properly does not mean that there is an actual mailbox at that location. There is no way in PHP to "check" if a email address exists/is active. That is the entire purpose of activation links, to verify that someone is checking that email address.
+1 for filter_var(). Use it instead of a simple regexp. Even the most complex regexp can't get every possible way of putting together an RFC 5322 compliant address. Your attempt to come up with something is pretty much guaranteed to fail.
But you didn't ask about address format verification, you asked about checking to see that the mail was sent. The whole purpose of an activation link is to validate the email address. If you clean up unvalidated accounts on a regular basis, it doesn't matter whether the email address is structured correctly. By sending a link, you're doing a full-circuit test that bypasses any possible format misinterpretations that filter_var() might have.

Categories