N-PN White-Hat Project
[Php] Sécurisation formulaire envoi de mail - Version imprimable

+- N-PN White-Hat Project (https://dev.n-pn.fr/forum)
+-- Forum : Programmation (https://dev.n-pn.fr/forum/forumdisplay.php?fid=72)
+--- Forum : Langages interprétés (https://dev.n-pn.fr/forum/forumdisplay.php?fid=27)
+--- Sujet : [Php] Sécurisation formulaire envoi de mail (/showthread.php?tid=2239)



[Php] Sécurisation formulaire envoi de mail - kaizo - 03-10-2012

Salut a tous !

J'ai sur mon site un formulaire d'envoi par mail en php avec captcha, et je voudrais savoir simplement si il est suffisamment sécurisé, alors je vous donne le code, merci à ceux qui prendront le temps de le regarder Shy

d'abord le formulaire:

Code :
<form id="contact" method="post" action="mail.php">
    <fieldset><legend>coordonn&eacute;es</legend>
        <p><label for="nom">Nom :</label><input type="text" id="nom" name="nom" tabindex="1" maxlength="20" size="20"/></p>
        <p><label for="prenom">Pr&eacute;nom :</label><input type="text" id="prenom" name="prenom" tabindex="1" maxlength="20" size="20" /></p>
        <p><label for="email">Email :</label><input type="text" id="email" name="email" tabindex="2" /></p>
    </fieldset>

    <fieldset><legend>message :</legend>
        <p><label for="objet">Objet :</label><input type="text" id="objet" name="objet" tabindex="3" /></p>
        <p><label for="message">Message :<br/></label><textarea id="message" name="message" tabindex="4" cols="50" rows="10"></textarea></p>
        <label for="code"> somme des deux nombres dans la case </label>  
        <img title="cap" src="captcha.php" alt="Cap" />  
        <input id="captcha"  name="captcha" type="text" maxlength="2" size="3"/>
    </fieldset>

    <div style="text-align:center;"><input class="bouton"  type="submit" name="envoi" value="Envoyer" /></div>
</form>


ensuite le script d'envoi mail.php (récupérer sur un site a l'origine, je sais plus où, et modifier ensuite) :

Code PHP :
$destinataire 'blabla@blabla.fr';

    
// copie ? (envoie une copie au visiteur)
    
$copie 'oui'

    
// Messages de confirmation du mail
    
$message_envoye "Votre message a &eacute;t&eacute; envoy&eacute; !";
    
$message_non_envoye "L'envoi du mail a &eacute;chou&eacute;, veuillez r&eacute;essayer SVP.<br/><a href=contact.php >Cliquez ici pour r&eacute;essayer</a>";

    
// Messages d'erreur du formulaire
    
$message_erreur_formulaire "Vous devez d'abord <a href=\"contact.php\">envoyer le formulaire</a>.";
    
$message_formulaire_invalide "V&eacute;rifiez .";
    
$message_captcha "R&eacute;sultat faux ! <br/>  ";
    
/*
        ********************************************************************************************
        FIN DE LA CONFIGURATION
        ********************************************************************************************
    */
    

    // on teste si le formulaire a été soumis
    
if (!isset($_POST['envoi']))
    {
        
// formulaire non envoyé
        
echo '<p>'.$message_erreur_formulaire.'</p>'."\n";
    }
    
//captcha
    
else if(isset($_POST['captcha'])) // Si on a validé le formulaire.
            
                
if($_SESSION['resultat_captcha'] != $_POST['captcha'])
                { 
// Si le résultat est faux.
                    
echo '<p class="mil">'.$message_captcha.'<br/> <a href="javascript:history.go(-1);">Retour au formulaire</a> </p>'."\n";
                }
                
    
    else
    {
        
/*
         * cette fonction sert à nettoyer et enregistrer un texte
         */
        
function Rec($text)
        {
            
$text trim($text); // delete white spaces after & before text
            
if (=== get_magic_quotes_gpc())
            {
                
$stripslashes create_function('$txt''return stripslashes($txt);');
            }
            else
            {
                
$stripslashes create_function('$txt''return $txt;');
            }

            
// magic quotes ? anti xss
            
$text $stripslashes($text);
            
$text htmlspecialchars($textENT_QUOTES); 
            
$text nl2br($text);
            return 
$text;
        };

        
/*
         * vérification syntaxe email
         */
        
function IsEmail($email)
        {
            
$pattern "#^([a-z0-9_]|\\-|\\.)+@(([a-z0-9_]|\\-)+\\.)+[a-z]{2,7}$#";
            return (
preg_match($pattern,$email)) ? true false;
        };

        
// formulaire envoyé, on récupère tous les champs.
        
$nom     = (isset($_POST['nom']))     ? Rec($_POST['nom'])     : '';
        
$prenom  = (isset($_POST['prenom']))  ? Rec($_POST['prenom'])  : '';
        
        
$email   = (isset($_POST['email']))   ? Rec($_POST['email'])   : '';
        
$objet   = (isset($_POST['objet']))   ? Rec($_POST['objet'])   : '';
        
$message = (isset($_POST['message'])) ? Rec($_POST['message']) : '';


        
// On va vérifier les variables et l'email ...
        
$email = (IsEmail($email)) ? $email '';

        if ((
$nom != '') && ($email != '') && ($objet != '') && ($message != ''))
        {
            
// les 4 variables sont remplies, on génère puis envoie le mail
            
$headers 'From: '.$nom.' <'.$email.'>' "\r\n";

            
// envoyer une copie au visiteur ?
            
if ($copie == 'oui')
            {
                
$cible $destinataire.','.$email;
            }
            else
            {
                
$cible $destinataire;
            };

            
// Remplacement de certains caractères spéciaux
            
$message str_replace("'","'",$message);
            
$message str_replace("’","'",$message);
            
$message str_replace("&quot;",'"',$message);
            
$message str_replace('<br>','',$message);
            
$message str_replace('<br />','',$message);
            
$message str_replace("&lt;","<",$message);
            
$message str_replace("&gt;",">",$message);
            
$message str_replace("&amp;","&",$message);

            


            
// Envoi du mail
            
if (mail($cible$objet$message$headers))
            {
            
            
            
                echo 
'<p class="mil">'.$message_envoye.'<br/><a href=index.php>Cliquez ici pour revenir &agrave; l\'accueil</a></p>'."\n";
            }
            else
            {
                echo 
'<p class="mil">'.$message_non_envoye.'</p>'."\n";
            };
        }
        else
        {
            
// une des 3 variables (ou plus) est vide ...
            
echo '<p class="mil">'.$message_formulaire_invalide.' <br/><a href="javascript:history.go(-1);">Retour au formulaire</a></p>'."\n";
        
        };
        
        
        
    }; 
// fin du if (!isset($_POST['envoi']))
    
    

?>

et enfin le captcha :

Code PHP :
<?php
session_start
(); // On ouvre une session, car on va en utiliser plus loin.
header ("Content-type: image/png"); // On indique le format de l'image.
$image imagecreate(80,20); // On indique les dimensions de l'image.
$fond imagecolorallocate($image255255255); // On renseigne ici la couleur de fond.
$couleur_texte imagecolorallocate($image44143228); // On indique la couleur du texte.

$nbre1 rand(1,10);
$nbre2 rand(1,10);
// On crée nos deux nombres avec chacun un chiffre aléatoire associé.

$_SESSION['resultat_captcha'] = $nbre1 $nbre2// Le résultat numérique de l'addition.
$_SESSION['addition'] = $nbre1.' + '$nbre2// L'addition sous forme textuelle.

imagestring($image622$_SESSION['addition'], $couleur_texte);
// Enfin on insère le texte avec la couleur précisée dans l'image.

imagepng($image); // On génère l'image.
imagedestroy($image); // On libère la mémoire associée à l'image.
?>

Voilà, merci encore aux bonnes âmes


RE: [PHP] Sécurisation formulaire envoi de mail - InstinctHack - 03-10-2012

Je regarde ca demain (je suis sur phone la... :/ )


RE: [PHP] Sécurisation formulaire envoi de mail - kaizo - 03-10-2012

pas de soucis, ya aucune urgence ^^


RE: [PHP] Sécurisation formulaire envoi de mail - supersnail - 03-10-2012

Bonjour,

IMHO y'a une petite "vulnérabilité" qui fait que ton captcha a une chance non nulle de ne servir à rien. En effet, un utilisateur peut forger une requête HTTP en envoyant un cookie PHPSESSID bidon, ce qui fera voir à PHP une nouvelle session... où la variable de session "resultat_captcha" n'a pas été définie (donc considérée comme "nulle" par PHP). Ainsi en foutant rien dans ton $_POST["captcha"], tu bypass sans problème le captcha.

Pour remédier à ce problème, faut juste faire un isset($_SESSION["resultat_captcha"]) et inviter l'utilisateur à GTFO si cette variable de session n'existe pas Wink


RE: [PHP] Sécurisation formulaire envoi de mail - Swissky - 03-10-2012

C'est pas vraiment une faille mais ton captcha se bruteforce assez simplement , les 2 valeurs pour l'addition étant très simple , chacune de 1 à 10 , les résultats possible sont donc de 0 à 20 .
tu compliquerais les choses avec des virgules ou alors des nombres sensiblement (0,1000) plus grand ou bien avec des captcha existant comme ceux de Google ^^
A la limite :

"Justin Richer 28-Mar-2012 06:43
Since many people (myself included) come to this page looking for a way to do a random string, I present a way that uses arrays and shuffle() instead of rand(). This also has the effect of not repeating any characters in the value set."
Code PHP :
$arr str_split('ABCDEFGHIJKLMNOP'); // get all the characters into an array
     
shuffle($arr); // randomize the array
     
$arr array_slice($arr06); // get the first six (random) characters out
     
$str implode(''$arr); // smush them back into a string 
Et tu demandes juste d'entrer la valeur affichée au lieu de faire une addition ^^


RE: [PHP] Sécurisation formulaire envoi de mail - kaizo - 04-10-2012

Merci d’avoir répondu Wink
(03-10-2012, 19h27)supersnail a écrit : Bonjour,

IMHO y'a une petite "vulnérabilité" qui fait que ton captcha a une chance non nulle de ne servir à rien. En effet, un utilisateur peut forger une requête HTTP en envoyant un cookie PHPSESSID bidon, ce qui fera voir à PHP une nouvelle session... où la variable de session "resultat_captcha" n'a pas été définie (donc considérée comme "nulle" par PHP). Ainsi en foutant rien dans ton $_POST["captcha"], tu bypass sans problème le captcha.

Pour remédier à ce problème, faut juste faire un isset($_SESSION["resultat_captcha"]) et inviter l'utilisateur à GTFO si cette variable de session n'existe pas Wink

pourtant si on ne met rien dans le captcha, il indique "résultat faux" grace a
Code PHP :
else if(isset($_POST['captcha'])) 
, alors comment peut on le bypasser en ne mettant rien ?

@swissky :
merci pour le code, je vais l'updater, mon captcha a trois ans et était censé être temporaire, mais parfois ya du provisoire qui dure ^^


RE: [PHP] Sécurisation formulaire envoi de mail - supersnail - 04-10-2012

Ben le truc c'est que si tu envoies "&captcha=" au serveur, bah ta variable est bien définie, mais elle est nulle.

isset détecte juste le fait que ta variable existe aux yeux de php ou non, pas si elle est nulle (c'est la fonction empty qui sert à ça Wink )


RE: [PHP] Sécurisation formulaire envoi de mail - CyberSee - 04-10-2012

Ça me fait penser, j'avais partager un post sur les captchas ici
http://n-pn.fr/forum/showthread.php?tid=1263

Code PHP :
if( $_SESSION['security_code'] == $_POST['security_code'] && !empty($_SESSION['security_code'] ) ) {   
// Le code est bon    
} else {  
echo 
"- Désolé, vous devez copier le contenu de l'image dans le champ sécurité.<br>$err";   




RE: [PHP] Sécurisation formulaire envoi de mail - kaizo - 05-10-2012

bon j'ai modifié mon code comme ceci :
Code PHP :
if($_SESSION['resultat_captcha'] != $_POST['captcha'] && empty($_SESSION['resultat_captcha'] ))
                { 
// Si le résultat est faux.
                    
echo '<p class="mil">'.$message_captcha.'<br/> <a href="javascript:history.go(-1);">Retour au formulaire</a> </p>'."\n";
                } 

j'ai donc rajouter && empty($_SESSION['resultat_captcha'] )

cela doit combler la brèche, non ?
en tout cas merci encore.

ps : ça pourrait presque faire partie d'un challenge de bypass de captcha Shy


RE: [PHP] Sécurisation formulaire envoi de mail - supersnail - 05-10-2012

Bonjour
Code PHP :
if($_SESSION['resultat_captcha'] != $_POST['captcha'] || empty($_SESSION['resultat_captcha'] )) 
serait mieux (sinon si le captcha est faux et que ta session n'est pas vide, le empty renvoie false et du coup la condition est fausse).


RE: [PHP] Sécurisation formulaire envoi de mail - kaizo - 05-10-2012

ah oui, pas faux ! merci pour la correction ^^