Viewed   67 times

Could you advise me how do I go about preventing email injection in PHP mail() without losing original message data? E.g. if I need to allow user to use rn, To, CC etc, so I do not want to completely strip them away from the message - I still want them delivered, but without adding any additional headers or somehow allowing mail injection to happen.

Most of the advices on internet suggest stripping that data away completely - but I do not want to do that.

I am sending plain text (non HTML) messages through PHP mail() function.

What would you advise?

 Answers

3

To filter valid emails for use in the recipient email field, take a look at filter_var():

$email = filter_var($_POST['recipient_email'], FILTER_VALIDATE_EMAIL);

if ($email === FALSE) {
    echo 'Invalid email';
    exit(1);
}

This will make sure your users only supply singular, valid emails, which you can then pass to the mail() function. As far as I know, there's no way to inject headers through the message body using the PHP mail() function, so that data shouldn't need any special processing.

Update:

According to the documentation for mail(), when it's talking directly to an SMTP server, you will need to prevent full stops in the message body:

$body = str_replace("n.", "n..", $body);

Update #2:

Apparently, it's also possible to inject via the subject, as well, but since there is no FILTER_VALIDATE_EMAIL_SUBJECT, you'll need to do the filtering yourself:

$subject = str_ireplace(array("r", "n", '%0A', '%0D'), '', $_POST['subject']);
Tuesday, September 20, 2022
4

It might not be the prettiest, but you're certainly not doing it "wrong". You're demonstrating classing constructor injection, but you could perhaps refactor to keep some of the disparate objects separated a bit more.

My suggestion would be to look at established PHP DI containers. See how they work, use them in a few apps, and (1) you'll have much more testable apps and (2) you'll be much more comfortable with DI in general.

Take a look at one or more of the following:

  • Pimple
  • Aura DI
  • Symfony DI
Saturday, November 5, 2022
 
5

All mail servers will add an Received header row to the message. You can configure your own server(s) to not add such a header, and even to remove other such headers, but you cannot control the behavior of other mail servers. This means that the first server outside your environment will add the IP and hostname of your last server, and there is nothing you can do about it.

Monday, December 19, 2022
 
3

In your form id="email" is conflicting with input id="email"

You can use HTML5 attributes for form validation (in HTML5 supported browsers)

http://www.the-art-of-web.com/html/html5-form-validation/#.UnDpBHMW3eU

Code

<?php
if(isset($_POST['submit'])) {
    print_r($_POST);
    die;
    $email_to = "emailaddress";
    $email_subject = "Mint Makeup & Beauty Enquiry";        

    $fname = $_POST['fname']; // required
    $lname = $_POST['lname']; // required
    $message = $_POST['message']; // required
    $email_from = $_POST['email']; // required

    // create email content
    $email_content = "From:"." ".$fname." ".$lname."n"."Email:"." ".$email_from."n"."Message:"." ".$message; 
    mail($email_to, $email_subject, $email_content);
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<script type="text/javascript">
function validateForm() { 
    var error = false;
    var error_string = 'Please correct the following errors:nn';  
    if (document.getElementById('fname').value == ""){
        error_string += "--> First name must be filled out.n";
        error = true;
    } 
    if (document.getElementById('lname').value == ""){
        error_string += "--> Last name must be filled out.n";
        error = true;
    } 
    if (document.getElementById('email').value == ""){
        error_string += "--> Email must be filled out.n";
        error = true;
    }    
    if(error){
        alert(error_string);
        return false;
    }  else {
        return true;
    }
}
</script>
</head>
<body>
<form onsubmit="return validateForm(this)"  action="" method="post" >

    <div id="form_fname">
    <label for="fname"><img src="images/firstname.png" width="94" height="17" alt="first name" /></label>
    <input type="text" name="fname" id="fname" />  
    </div>   

    <div id="form_lname">
    <label for="lname"><img src="images/lastname.png" width="89" height="17" alt="last name" /></label>
    <input type="text" name="lname" id="lname" />  
    </div>   

    <div id="form_email">
    <label for="email"><img src="images/email.png" width="53" height="17" alt="email" /></label>
    <input type="text" name="email" id="email" />   
    </div>

    <div id="form_message">   
    <label for="Message"><img src="images/message.png" width="77" height="17" alt="message" /></label>
    <textarea name="message" id="message" cols="45" rows="5"></textarea>  
    </div>

    <div id="form_submit"> 
    <input type="submit" name="submit" id="submit" value="Submit" />
    </div>

  </form>
  </body>
  </html>

I just showed you how client side validation works and form is posting correctly.. You should always use server side validation..

Thursday, August 25, 2022
4

You haven't answered the question "How do you intent to talk to the MS SQL database if PDO isn't allowed", but I assume there are the mssql_* functions to be used.

These do not have an escaping function readymade, but it seems they offer you to use prepared statements - which will do the job.

Otherwise you would have the security-relevant task to create an escaping function yourself. The character replacement is not really complicated when you first look at it, and you might be lucky to only have to cover your exact use case with a defined encoding. So this might really be as easy as looking up in the MSSQL manual which characters in a string are not allowed as a simple character, and how to escape them.

Be alerted though that you might miss edge cases, and if you can avoid it, I'd rather use the prepared statement feature.

Update: I misread the manual, mssql_execute() only calls stored procedures, not prepared statements. Can't you store procedures? Would be an easy way out. But I'd like to know how you are supposed to talk to the database anyways.

Update2: I found a link in a comment on php.net for mssql_bind pointing back to an SO answer about escaping: How to escape strings in SQL Server using PHP?

Tuesday, October 25, 2022
 
lfk
 
lfk
Only authorized users can answer the search term. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :