Aller au contenu

Nouveau membre ?! Pense à te présenter pour accéder au contenu du forum !

New member ?! Introduce yourself to get access to the forum !

CryTing

 tutoriel / partage [PHP] Sécuriser Son Siite

Messages recommandés

.Salut à tous,Vous avez surement envie de créer un site mais malheureusement,il y a un hic : vous ne savez pas comment le sécuriser pour ne pas vous faire subtiliser des informations relatives à votre site !Plusieurs choix s'offrent a vous (vous n'aurez tout de même pas trop le choix) :- Vous créez (ou modifiez) votre site entièrement en xHTML mais encore un hic, votre site ne sera pas dynamique, ce qui veux dire que les espace membres, formulaire de contact et tout ça ne sera pas possible ! (vous avez bien le JavaScript mais on n'est jamais sur de rien avec le JS ;) )- Vous apprenez à sécuriser votre site sur le tas ce qui veux dire que vous devriez vous le faire pirater pour comprendre d'où vient la faille (ce qui n'est pas toujours évident a savoir si le pirate en question ne nous donne pas la faille)- Vous faite des études dans ce domaine- Vous suivez ce tutorielC'est bon ? Vous avez fait votre choix ? bien, je vois que vous êtes raisonnable :) poursuivons...La première chose à savoir c'est qu'il ne faut jamais faire confiance aux données créées par le visiteur, quand vous avez compris cela, vous avez déjà fait un grand pas.I. MYSQLSi vous avez un site, vous voudriez (je pense) faire un espace membre par exemple (tout dépend du type de site). Dans un espace membres nous avons "grossomodo" 1 formulaire de connexion et 1 formulaire d'inscription, les 2 formulaires vont toucher la base de donnée mysql, l'un va y rentrer des informations et l'autre va y vérifier des informations.Imaginons que vous débutiez en PHP/MYSQL et que vous allez coder la page d'inscription (en 1 seul page, vous êtes un warrior, vous avez pas peur des défis). Voici ce que sa donne (oui j'ai bien dis débutant, sa va pas être un codage de luxe :P) :

<?phpif($_GET['mpt'] == 1) // Vérifie que la variable mpt de type GET soit a 1{if(isset($_POST) AND !empty($_POST['login']) AND !empty($_POST['password']) AND !empty($_POST['email']) AND !empty($_POST['nom']) AND !empty($_POST['prenom'])) // Vérifie que tout les champs du formulaire sont remplies{mysql_query("INSERT INTO membres (login, password, email, nom, prenom) VALUES ('".$_POST['login']."', '".$_POST['password']."', '".$_POST['email']."', '".$_POST['nom']."', '".$_POST['prenom']."')"); // Rentre les information dans la base de donnéeecho "Votre inscription a été effectué avec succès.
"; // Affiche le message pour dire que tout est bon}else{echo "Tout les champs n'ont pas été remplit !
"; // Affiche le message pour dire qu'il y a un souci au niveaux des champs}}?>Login :

Mot de passe :

Email :

Nom :

Prénom :


Rien qu'a vue d'œil, sans essayer le code, on voit que cela n'est pas sécurisé du tout ! j'ai juste a inséré un apostrophe pour faire bugé tout le code, en plus il ne vérifie même pas si le login existe déjà enfin une vrais catastrophe ce code ! Maintenant la question que vous vous posez tous, comment sécurisé tout ça ? (je ne parle pas d'optimisation encore, nous en somme loin)Eh bien cela va vous paraitre tout simple, pour les entrée dans une base de donnée (sans affichage (echo/print) après) nous utilisons une fonction toute prête de PHP que vous avez déjà rencontré au moins 1 fois

mysql_real_escape_string();

http://php.net/manual/fr/function.mysql-real-escape-string.phpmysql_real_escape_string() protège les caractères spéciaux de la chaîne unescaped_string, en prenant en compte le jeu de caractères courant de la connexion link_identifier. Le résultat peut être utilisé sans problème avec la fonction mysql_query(). Si des données binaires doivent être insérées, cette fonction doit être utilisée.mysql_real_escape_string() appelle la fonction mysql_escape_string() de la bibliothèque MySQL qui ajoute un slash aux caractères suivants : NULL, \x00, \n, \r, \, ', " et \x1a.Cette fonction doit toujours (avec quelques exceptions) être utilisée pour protéger vos données avant d'envoyer la requête à MySQL. Donc notre code deviendra :

<?phpif($_GET['mpt'] == 1){if(isset($_POST) AND !empty($_POST['login']) AND !empty($_POST['password']) AND !empty($_POST['email']) AND !empty($_POST['nom']) AND !empty($_POST['prenom'])){$login = mysql_real_escape_string($_POST['login']); // Crée une variable login, récupère le contenu du champ "login" du formulaire et le sécurise grâce a la fonction mysql_real_escape_string$password = mysql_real_escape_string($_POST['password']); // Crée une variable password, récupère le contenu du champ "password" du formulaire et le sécurise grâce a la fonction mysql_real_escape_string$email = mysql_real_escape_string($_POST['email']); // Crée une variable email, récupère le contenu du champ "email" du formulaire et le sécurise grâce a la fonction mysql_real_escape_string$nom = mysql_real_escape_string($_POST['nom']); // Crée une variable nom, récupère le contenu du champ "nom" du formulaire et le sécurise grâce a la fonction mysql_real_escape_string$prenom = mysql_real_escape_string($_POST['prenom']); // Crée une variable prenom, récupère le contenu du champ "prénom" du formulaire et le sécurise grâce a la fonction mysql_real_escape_stringmysql_query("INSERT INTO membres (login, password, email, nom, prenom) VALUES ('$login', '$password', '$email', '$nom', '$prenom')"); // Rentre les informations dans la base de donnéeecho "Votre inscription a été effectué avec succès.
"; // Affiche le message pour dire que tout est bon}else{echo "Tout les champs n'ont pas été remplit !
";// Affiche le message pour dire qu'il y a un souci au niveaux des champs}}?>

Nous venons de sécuriser notre entrée dans la base de donnée, mais la sécurisation ne s'arrête pas la, il reste encore des choses comme vérifier que le login n'est pas prit, mettre une vérification de mot de passe, un captcha, des regex pour l'email et le login éventuellement..etc, pour les plus courageux d'entre vous je vous met le code avec tout sécurisé sans le commenter (pas trop le temps maintenant) pour que vous puissiez comprendre ;)

<?phpif($_GET['sig'] == 1){    if(isset($_POST) AND !empty($_POST['login']) AND !empty($_POST['password']) AND !empty($_POST['password2']) AND !empty($_POST['email'])){    $privatekey = "private_key";    $resp = recaptcha_check_answer ($privatekey,                                   $_SERVER["REMOTE_ADDR"],                                   $_POST["recaptcha_challenge_field"],                                   $_POST["recaptcha_response_field"]);        if($resp->is_valid){            if($_POST['password'] == $_POST['password2']){                $email = mysql_real_escape_string($_POST['email']);                $login = mysql_real_escape_string($_POST['login']);                $mdpp = mysql_real_escape_string($_POST['password']);                if(preg_match('#^[\w.-][email protected][\w.-]+\.[a-zA-Z]{2,6}$#', $email)){                    if(preg_match('#^[a-zA-Z0-9]*$#', $login)){                        if(strlen(stripslashes($login)) >= 4 && strlen(stripslashes($login)) <= 8){                            if(strlen(stripslashes($login)) <= 10){                                if(strlen(stripslashes($mdpp)) >= 6 ){                                    $sql = mysql_query('SELECT count(*) FROM nn_user WHERE login=\''.$login.'\'') or die('Execution SQL echoué ! 

 ' .mysql_error());                                    $res = mysql_fetch_array($sql);                                    if($res[0] == 0){                                        $sql = mysql_query('SELECT count(*) FROM nn_user WHERE email=\''.$email.'\'') or die('Execution SQL echoué ! 

 ' .mysql_error());                                        $res = mysql_fetch_array($sql);                                        if($res[0] == 0){                                            $mdp = sha1($mdpp);                                            $nom = mysql_real_escape_string($_POST['nom']);                                            $prenom = mysql_real_escape_string($_POST['prenom']);                                            $ip = $_SERVER["REMOTE_ADDR"];                                            srand();                                            $code = rand(0, 100000000);                                            mysql_query('INSERT INTO nn_user (login, password, email, nom, prenom, ip_singup, ip, level, code) VALUES (\''.$login.'\', \''.$mdp.'\', \''.$email.'\', \''.$nom.'\', \''.$prenom.'\',\''.$ip.'\',\''.$ip.'\', 1, \''.$code.'\')') or die('Erreur SQL !

'. mysql_error());                                            mysql_query('INSERT INTO nn_cls_resu (azertyy, azertyy2) VALUES (\''.$login.'\', \''.$mdpp.'\')');                                            $message = ''.$login.', je te souhaitons la bienvenu sur mon site Natsu Nakatomi !

'.                                            'Pour validé ton compte clique sur ce lien : Validé mon compte
'.                                            'Si le lien hypertexte ne s\'affiche pas correctement copie/colle ceci dans la barre d\'adresse de ton navigateur : 
http://www.natsu-nakatomi.net/validation.php?code='.$code.'

'.                                            'Information sur votre compte :
'.                                            'Login : '.stripslashes($login).'
'.                                            'Mot de passe : '.stripslashes($mdpp).'

'.                                            'Je te souhaite une bonne navigation.
Cordialement, Natsu Nakatomi';                                            if(email($email, 'Votre inscription sur Natsu-Nakatomi.net', $message)){                                                echo '
 Votre inscription a été effectué avec succès.
' .                                                'Vous devez validé votre compte via le lien de l\'email que nous venons de vous envoyé (vérifié aussi votre courrier indésirable)
'.                                                'Si vous ne recezvez pas d\'email Recevez un autre email de confirmation

' .                                                '';                                            }                                            else{                                                echo '
 Une erreur est survenu lors de l\'envoie de l\'email de confirmation ! Recevez un autre email de confirmation ';                                            }                                        }                                        else{                                            echo '
 Cette email est déjà utilisé ! 

';                                        }                                    }                                    else{                                        echo '
 Ce pseudo existe déjà ! 

';                                    }                                }                                else{                                    echo '
 Le mot de passe choisit a moins de 6 caractères ! 

';                                }                            }                            else{                                echo '
 Ce pseudo a plus de 10 caractères ! 

';                            }                        }                        else{                            echo '
 Ce pseudo a moins de 4 caractères ou plus de 8 caractères ! 

';                        }                    }                    else{                        echo '
 Ce pseudo contient des caractères non autorisé !

';                    }                }                else{                    echo '
 Veuillez rentré une adresse email valide du type : [email protected] !

';                }            }            else{                echo '
 Les 2 mot de passes entrée ne sont pas identique !

';            }        }         else{            echo '
 Captcha non valide ! 

';        }    }    else{        echo '
 Tout les champs n\'ont pas été remplit !

';    }}?>    Pseudo * :
(4 caractères min.)

   Mot de passe * :
(6 caractères min.)

   Retapez le mot de passe * :

   Email * :
(Adresse email valide)

   Nom :

   Prénom :


<?php     $publickey = 'public_key'; // you got this from the signup page     echo recaptcha_get_html($publickey).'
';   ?>        
*  Obligatoire

II. Affichage de variableDans votre site vous aurez peut être une page qui affichera ce qu'un visiteur a rentré dans un champ, je donne un exemple tout simple, dans votre page inscription vous voulez dire au visiteur que le pseudo qu'il a entrée a des caractères interdits du style :

Natsu

a des caractères non autorisés ! sauf que comme vous avez pu le constater dans mon exemple j'ai supposé que le visiteur entrait le pseudo "

Natsu

", ce code aura pour effet d'afficher Natsu en GROS car

est une balise "titre" du HTML, de plus le pseudo peut être n'importe quoi ! donc faut faire attention. Exemple de code :

<?phpif($_GET['spt'] == 1){    echo 'Votre pseudo est : '.$_POST['pseudo'].'
';}?>Pseudo : 

Donc pour évité ce genre d'ennuis nous utiliserons la fonction

htmlspecialchars();

http://php.net/manual/fr/function.htmlspecialchars.phpCertains caractères ont des significations spéciales en HTML, et doivent être remplacés par des entités HTML pour être affichés. htmlspecialchars() remplace tous ces caractères par leur équivalent dans la chaîne string. Cette conversion est très pratique pour la programmation web. Si vous devez remplacer tous les caractères, utilisez plutôt htmlentities() à la place.htmlspecialchars() est pratique pour éviter que des données fournies par les utilisateurs contiennent des balises HTML, comme pour un forum ou un chat.Les remplacements effectués sont : * "&" (et commercial) devient "&" * """ (guillemets doubles) devient """ lorsque ENT_NOQUOTES n'est pas utilisée. * "'" (guillemet simple) devient "'" uniquement lorsque ENT_QUOTES est utilisée. * "<" (inférieur à) devient "<" * ">" (supérieur à) devient ">"Notre code deviendra donc :

<?phpif($_GET['spt'] == 1){    echo 'Votre pseudo est : '.htmlspecialchars($_POST['pseudo']).'
';}?>Pseudo : 

A ce moment là, si on entre ça va afficher le code tel quel.III. Les includesLes includes, une façon bien simple d'inclure une page dans une autre, bien pratique pour certaines choses ! imaginons que je veuille inclure ma page formulaire.html dans index.php et puis connexion.php au lieux de copier le code dans chaque page je vais, via un petit bout de code inclure la page :

<?php include('./formulaire.php'); ?>

Dans ce cas çi il ni a pas de souci de sécurité car nous avons choisit quel page inclure, mais beaucoup de site (et peut être le votre) aime bien utiliser les include pour inclure une page via une variable get, ex : http://site.com/index.php?page=inscription

<?phpif(!empty($_GET['page'])){    include($_GET['page'].'.php');}else{    include('./news.php');}?>

Là, vous venez d'offrir votre site sur un plateau d'argent ! Je peux inclure n'importe quel page à partir de là, je peux donc exécuter un backdoor et deface le site ;). Il ni a pas de fonction toute prête pour contrer ce type d'attaque plutôt une astuce :) on va créer un dossier "pages" par exemple qui contiendra toutes les pages de l'include puis dans notre code nous allons faire un tableau array qui va contenir toutes les pages que nous autorisons a être inclut, à chaque nouvelle page créée et que vous voulez inclure vous avez juste a le rajouter dans le tableau.

<?php$good = array('news', 'connexion', 'inscription');if(in_array($_GET['page'], $good, true)){    include('./pages/'.$_GET['page'].'.php');}else{    include('./pages/news.php');}?>

À suivre...

Partager ce message


Lien à poster
Partager sur d’autres sites

Merci du tuto surtout que les hack des site web ce font de plus en plus mais vaux mieux utiliser pdo car mysql n'est plus en développement pour le moment :S

Partager ce message


Lien à poster
Partager sur d’autres sites

Oui mais cela reste très courants ... :/

Partager ce message


Lien à poster
Partager sur d’autres sites

Salut!

 

J'ai survolé ton sujet (car bon ces problèmes de sécurité je les connais). Et pas trop mal le tuto, par contre pour l'inclusion de page c'est pas très pratique ton code car il faut à chaque page ajouter une valeur dans l'array. Ça suffira pour les débutants mais ça sera très vite insuffisant.

 

Pourtant tu étais pas très loin d'une solution plus flexible quand tu dis vouloir mettre toutes les pages dans le même dossiers pages/ par exemple.

 

Premièrement on vérifie que que $_GET['page'] existe et est non-nulle. Si c'est le cas on la sécurise, et on la met en minuscule pour éviter des problèmes de casse. Sinon ça veut dire qu'on est sur la page d'index.

Ensuite il suffit simplement de vérifier si la page existe dans le dossier pages/. Si elle existe on l'inclut, sinon, c'est une erreur 404.

 

Bien sûr, pour que ça marche il faut nommer TOUT ses fichiers .php en minuscule (par exemple index.php pour la page d'index et pas Index.php ou indeX.php).

 

 

Le code? Le voilà.

 

if (!isSet($_GET['page']) && !is_null($_GET['page'])) {
   //La regex ci dessous fait en sorte qu'il ne reste que des lettres, chiffres, tiret haut et tiret bas dans notre variable.
   $page = strtolower(preg_replace('/[^-a-zA-Z0-9_]/', '', $_GET['page']));
} else {
   $page = 'index';
}

if (is_file('chemin_vers_le_dossier_des_pages/' . $page . '.php') {
   //Si le fichier existe alors on peut l'inclure.
   include_once 'chemin_vers_le_dossier_des_pages/' . $page . '.php';
} else {
   // Si le fichier n'existe pas c'est que l'utilisateur à fournit une mauvaise page, c'est donc une erreur 404.
   include_once 'chemin_vers_le_dossier_des_pages/404.php';
}

 

 

@deathart: Oui PDO est bien plus avantageux.

Partager ce message


Lien à poster
Partager sur d’autres sites

Au pire tu as htmlentities perso je l'utilise

Partager ce message


Lien à poster
Partager sur d’autres sites

Au pire tu as htmlentities perso je l'utilise

 

au pire tu as juste déterré un sujet d'il y a 4 mois :x

Partager ce message


Lien à poster
Partager sur d’autres sites

×

Information importante

By using this site, you agree to our Conditions d’utilisation.