Email-injection

Un article de Le wiki de 2 noisettes - noisette.ch.

Sommaire

L'injection d'emails

Qu'est-ce que c'est ?

L'email injection est l'action d'utiliser la fonction mail d'un site web pour envoyer des mails à des personnes quelconques.

Les formulaires de contacts sont les cibles idéals, car ils se composent :

* un champ expéditeur
* un champ sujet
* un champ texte ou commentaire

Puis le bout de code responsable de l'envoi du mail ressemblera à quelque chose du style :

<?
// si l'utilisateur a cliqué sur le bouton "send"
if (isset($_POST['send'])) { 
    mail("the_contact_email", $_POST['sujet'], $_POST['commentaire'], "From: " . $_POST['expediteur'] . "\n");
}
?>

Bien que l'adresse du destinataire est écrit dans le fichier, on va voir qu'il y a différents moyen d'outre passer cette restriction et d'envoyer le mail à n'importe qui d'autre.

C'est grave docteur ?

Le mail envoyé par injection contiendra dans son en-tête les informations concernant le serveur qui héberge ce formulaire. Ceci permet de rester totalement anonyme. Quelle aubaine pour les spammeurs !

Une solution

Une solution est de mieux vérifier le contenu des variables et interdire l'usage de headers spécifiques.

Voici une fonction email qui opère quelques tests avant d'envoyer le mail. A utiliser massivement, pour le bien de votre formulaire de contact et celui de votre hébergeur :

/*
 * Check if the param is a valid email address
 */
function isValidEmail($email) {
        return (preg_match('/^[A-z0-9][\w\.\-]*@[A-z0-9][\w\.\-]+\.[A-z0-9]{2,6}$/', $email));
}

/*
 * Check for injection content in the param
 * Return true or false.
 */
function isValidStrings($string) {
        $badStrings = array("Content-Type:", "MIME-Version:", "Content-Transfer-Encoding:", "bcc:", "cc:");
        foreach($badStrings as $v){
                if(strpos($string, $v) !== false){
                        return false;
                }
        }
        return true;
}

/*
 * Sanitized email function which avoid [b]?cc injection
 * Send the email and return true, or return false without sending the email.
 *
 */
function email($to, $subject, $body, $headers = "") { 

        $verbose = true; 

        /*
         * Check the $to parameter
         */
        if (!isValidEmail($to)) {
                if ($verbose) echo "The recipient email isn't valid.";
                return false;
        }
        if (!isValidStrings($to)) {
                if ($verbose) echo "The recipient contains illigal characters.";
                return false;
        } 

        /*
         * Check the $subject parameter
         */
        if (!isValidStrings($subject)) {
                if ($verbose) echo "The subject contains illigal characters.";
                return false;
        } 

        /*
         * Check the $body parameter
         */
        if (!isValidStrings($body)) {
                if ($verbose) echo "The body contains illigal characters.";
                return false;
        }

        /*
         * Check the $headers parameter
         */
        if (!isValidStrings($headers)) {
                if ($verbose) echo "The headers contains illigal characters.";
                return false;
        }

        mail($to, $subject, $body, $headers);
        if ($verbose) echo "Email sent";
        return true;
}
 

/*
 * Simple usage : include the previous functions above your call to mail(),
 * and then replace the mail() call by email().
 */
email("the_email@the_domaine.ext", "Fonction mail()", "Voici une fonction mail() saine.");

Ressources