-->

Escape string to use in mail()

2020-01-25 08:30发布

问题:

Sure thing, when using MySQL you use mysqli_real_escape_string() and check that the type of input received is the kind you expect (string, number, etc) and you can be pretty sure you can use it as input to mysqli_query() quite securely... right?

Well, the questions are:

  • What is the best way to escape a string that's going to be used in mail()?
  • If the email recipient will be the email address entered in a text field, what things should I be careful about to avoid injections or exploits?

I have a pretty good idea how to do this but I'm digging into best practices on this subject to know if I'm missing something, or if there's a better way.


EDIT: The idea of this question is not to have THE answer, but to make a comprehensive collaborative list of all the things to take care of when doing email with PHP.

回答1:

The idea behind email-injection is that attacker inject line feed (LF) in the email headers and so he adds as many headers as he wants. Stripping those line feeds will protect you from this attack. For detailed info check http://www.phpsecure.info/v2/article/MailHeadersInject.en.php

The best practice is to rely on a well-written, frequently updated and widely-used code. For that I would suggest using PEAR_MAIL OR Zend_Mail

If you don't want to load those modules or you need to keep things very simple. You can extract the filtering functionality from those modules. Although I do recommend to use them and frequently update the library so that if new attack appears in future you will just need to update your library (Pear or Zend) and you are done.

This is the function that sanitize headers in Pear Mail package:

function _sanitizeHeaders(&$headers)
{
    foreach ($headers as $key => $value) {
        $headers[$key] =
            preg_replace('=((<CR>|<LF>|0x0A/%0A|0x0D/%0D|\\n|\\r)\S).*=i',
                         null, $value);
    }
}

Zend_Mail uses different filter for email,name and other fields:

function _filterEmail($email)
{
    $rule = array("\r" => '',
                  "\n" => '',
                  "\t" => '',
                  '"'  => '',
                  ','  => '',
                  '<'  => '',
                  '>'  => '',
    );

    return strtr($email, $rule);
}

function _filterName($name)
{
    $rule = array("\r" => '',
                  "\n" => '',
                  "\t" => '',
                  '"'  => "'",
                  '<'  => '[',
                  '>'  => ']',
    );

    return trim(strtr($name, $rule));
}

function _filterOther($data)
{
    $rule = array("\r" => '',
                  "\n" => '',
                  "\t" => '',
    );

    return strtr($data, $rule);
}