Améliorer et confirmer super formulaire php sécurisé.

Fermé
maverick13 Messages postés 9 Date d'inscription lundi 5 novembre 2012 Statut Membre Dernière intervention 6 avril 2013 - 5 nov. 2012 à 22:38
maverick13 Messages postés 9 Date d'inscription lundi 5 novembre 2012 Statut Membre Dernière intervention 6 avril 2013 - 6 nov. 2012 à 03:44
Bonjour,

Après des jours de travail j'ai terminé et testé un code de traitement d'un formulaire php avec toutes (toutes est un grand mot ! ) la sécurité suggéré sur le web.

Je le trouve vraiment idéal pour moi et j'aimerais que des pros me dise si je devrais ajouter encore plus de sécurité. Cet exemple( comme bien d'autres ) pourrait aider les débutants et intermédiaire à sécuriser leur formulaire davantage.

Je pense à, peut-être , allonger la liste des termes refusés avec des REGEX qui empêcherons toute balise html, javascript, flash, etc.. !?

- Penser à utiliser htmlentities() et compagnie pour afficher le résultat de vos formulaires au cas ou tout les sécurités mentionnés ici n'aurais pas été suffisante -

Voilà ce que le formulaire fait :
( Pour de l'upload il est suggérée de choisir un dossier de destination protégé par un .HTACCESS )
(Avec un autre preg_match on peut limiter l'utilisation de mots vulgaires )

. Dans le cas d'une possible attaque pirate un courriel d'alerte est envoyé
. Il change le nom du fichier à uploader avec un timestamp pour ne pas qu'il y ai deux fichier du même nom et pour qu'il soit identifiable ( je suggère d'y ajouter l'ID du client )
. Il valide l'extension de l'image uploader pour ne pas voir de fichier pirate php.
. Après avoir uploader une image avec la bonne extension il scan l'image pour vérifié qu'il n'y ai pas de balise php à l'intérieur et efface le fichier si le résultat est positif.
. Il contrôle le poids du fichier uploader.
. Il scan le retour des champs du formulaire pour ne pas qu'il y ai de balise php.
. Un petit '' mysql_real_escape_string'' contre les injections sql.
. Sans affichage des erreurs SQL.
. L'arborensence de mes répertoires est caché avec des index.php dans chaque dossier.

Voilà, sans prétention, j'espère qu'on pourra encore l'améliorer.

( Vous enlèverai surement quelques écho inutile ;)

Je n'ai pas développé la partie USER/LOGIN pour rendre le tout encore plus privé en plus de pouvoir effectué un suivi des possible attaque. Je reviendrai quand je l'aurai complèté.

Voici le formulaire html :

<form action="traitement.php" method="post" enctype="multipart/form-data" >
          

     <p><br />
      <label for="description1">
        Étape 1
      </label>
      <br />
      <textarea id="description1" name="etp1" rows="3" cols="15"></textarea>
    </p>
    
      <p><br />
      <label for="description2">
        Étape 2
      </label>
      <br />
      <textarea id="description2" name="etp2" rows="3" cols="15"></textarea>
    </p>
    
     <p><br />
      <label for="description3">
        Étape 3
      </label>
      <br />
      <textarea id="description3" name="etp3" rows="3" cols="15"></textarea>
    </p>
    
     <p><br />
            <label for="image">
            Photo de la recette
          </label>
          <br />
          <input type="file" id="image" name="image_up" />
          </p>
       
        <p><br />
      <input type="submit" name="valider" value="Envoyez" />

    </p>
        </form>


Et le code traitant php :

<?php
include("connect.php");

error_reporting(E_ALL & ~E_NOTICE);//Enlevé cette ligne pendant le dévelloppement.

$tabExt = array('jpg','gif','png','jpeg'); // Extensions autorisées
$extension = '';

$time = time();
$tmp= basename($_FILES['image_up']['name']);
$target = "images/";
$target .= $time.$tmp;
$nom_final = preg_replace ("' 'i","",$target);

// On vérifie la taille de l'image
if(filesize($_FILES['image_up']['tmp_name'])<101200) 
{
 // Récupération de l'extension du fichier
$extension = pathinfo($_FILES['image_up']['name'], PATHINFO_EXTENSION);
 
// On vérifie l'extension du fichier
if(in_array(strtolower($extension),$tabExt))
{
        // On transfert le fichier dans son dossier de destination ( /images )
	if(move_uploaded_file($_FILES['image_up']['tmp_name'], $nom_final)) 
	{
		echo "Le fichier ". basename( $_FILES['image_up']['name'])." a bien été transféré <br />";
	} else {
		echo "Désolé, il y eu un problème lors du transfert";
	}
} else {
	echo "Désolé, ce fichier n'est pas une image  <br />";
	mail('info@toto.com', 'attaque ', 'pirate $USER_ID');
}
}  else {
	echo "Désolé le fichier excède la limite permise <br />";
}
// On vérifie s'il y a eu upload.
if (file_exists($nom_final)) 
{
// Scan du fichier pour les balise php.
$fp = file_get_contents($nom_final);
   if(preg_match(''<\?php|<\?|\?>'i', $fp))
    {
   echo "méchant pirate !  code php dans l'image, intruder !  Intruder !  <br />";
   // On supprime le fichier.
   unlink($nom_final);
    mail('info@toto.com', 'attaque ', 'pirate $USER_ID'); 
    }
else {
		echo "pas de code php dans l'image. <br />";
	}
} else {
echo ("le fichier '$nom_final' n'existe pas <br />");
} 


	
        if (isset ($_POST['valider'])){
            //On récupère les valeurs entrées par l'utilisateur :
            $bb=mysql_real_escape_string($_POST['etp1']);
            $cc=mysql_real_escape_string($_POST['etp2']);
            $dd=mysql_real_escape_string($_POST['etp3']);
          
		
            //On construit la date d'aujourd'hui
            //strictement comme sql la construit
            $today = date("y-m-d");
           
        //On se connecte
            connectincludeconnect();
              	  
     $chaine = $bb.$cc.$dd;

     if(preg_match(''<\?php|<\?|\?>'i', $chaine))
     {
          echo "Méchant pirate tu veux mettre du code php dans les champs de formulaire<br /> ";
		  mail('info@toto.com', 'attaque ', 'pirate $USER_ID');
     }
     else
     {
          echo 'Transfert sql ok bon formulaire propre.  <br />';
		              //On prépare la commande sql d'insertion
            $sql = 'INSERT INTO recettes(ID,date,etp1,etp2,etp3) VALUES("","'.$today.'","'.$bb.'","'.$cc.'","'.$dd.'")'; 
                            
            mysql_query ($sql) 
                            
            // on ferme la connexion
            mysql_close();
     }
        }
        ?>


A voir également:

2 réponses

Atropa Messages postés 1940 Date d'inscription mercredi 25 juin 2008 Statut Membre Dernière intervention 11 mai 2014 274
6 nov. 2012 à 03:02
bonsoir,

pour la sécurité d'un formulaire, il faut un jeton et pour les fichiers il faut vérifier le type mime en plus de l'extension.
inutile de regarder a l'intérieur si il y a du php.
si le serveur est bien configuré il n'y a pas de risque qu'il soit exécuté si ce n'est pas un fichier php

envoyer un mail avec l'id de l'utilisateur est complètement inutile surtout pour une extension qui n'est pas valide. tu risque de spammer ta boite mail et de ton façon quelqu'un qui veut pirater ton site n'utilisera pas un vrai utilisateur ou l'utilisateur ne lui appartiendra pas

plus généralement passer toutes les variables externes à htmlentities à l'aide d'une unique fonction au début de chaque page. htmlentitie empêche aussi l'insertion de php et de toute façon si ce qui est entré dans le formulaire n'est pas écrit en dure dans un fichier php et qu'il n'est pas inclut dans le code il ne sera pas exécuté même si il en contient
faire très attention aux failles include qui peuvent permettre de récupérer n'importe quel fichier sources

pour sql il faut utiliser les requêtes préparé de pdo qui rendent les injections sql impossible si elle sont bien faite sans avoir a passer par une fonction de sécurisation

pour les mots de passe ils doivent être hashé avant d'être stocké en sha256 au minimum et avec une chaine de caractère concaténé au début ou a la fin avant le hash pour éviter les comparaison des hash.

ensuite pour la vérification il doivent juste être comparé jamais stocké plusieurs fois ou avoir des valeur nul

ne pas compté sur les langages client pour la sécurité. toutes les requêtes peuvent facilement être écrites à la main.

un fichier appelé par xhr ou autre est aussi vulnérable qu'un autre... (ca parait con mais ça arrive souvent qu'ils ne soient pas protégé comme il faut)

faire attention que les fichiers a inclure ne soit pas accessible directement

pour ce qui et de l'identification ou de l'inscription

pour l'inscription il faut un jeton et un captcha hasher le passe et le stocker
pour l'identification un jeton (comme pour tout formulaire) et pour vérifier le mot de passe il faut le hasher et le rechercher en même temps que le pseudo

par exemple SELECT id FROM membre WHERE identifiant = :ident && pass = :pass LIMIT 1

ne jamais sortir le mot de passe de la base de donnée et ne jamais le stocker autre part !!!

il faut aussi mettre un captcha au bout de 3 mot de passe erroné pour un identifiant ou une ip

un mail peut être envoyé a la limite si un formulaire est envoyé sans avoir le bon jeton mais ce n'est même pas sur que ce soit pour une tentative de piratage
0
Atropa Messages postés 1940 Date d'inscription mercredi 25 juin 2008 Statut Membre Dernière intervention 11 mai 2014 274
Modifié par Atropa le 6/11/2012 à 03:06
j'oubliais,

quand il y a une identification il faut aussi vérifier sur chaque page l'identité et la cohérence du visiteur, notamment les droits attribué a son id

j'espère avoir fait le tour
0
maverick13 Messages postés 9 Date d'inscription lundi 5 novembre 2012 Statut Membre Dernière intervention 6 avril 2013
6 nov. 2012 à 03:44
Faire le tour, faire le tour, Wow, je ne m'attendais pas à autant d'amélioration :).

Disons que je vais retourner à mes devoirs et re-proposer d'ici quelques jours un code plus efficace, niveaux sécurité.
Si j'ai bien compris.

Donc, quand on tape '' sécuriser son formulaire php '' sur google, tous les principales résultats de solutions ne sont que très peux efficace ? Peut-être est-ce trop complexe d'appliquer les recommandations vraiment efficace ?

Je vais plancher sur le sujet et revenir pour la suite.

Merci encore.
0