Aller au menu - Aller au contenu

[Plan du site] Vous êtes ici --- > Le Site du Zéro > Les tutoriels > Non-Officiels > Site Web > PHP > Optimisation & Sécurité > Lecture du tutoriel

Includes sécurisés et infinis

Avatar
Auteur : Asibasth
Créé : le 30/08/2006 00:09:33
Modifié : le 22/09/2007 18:53:07
Noter et commenter ce tutoriel
Imprimer ce tutoriel
Vous vous apprêtez à lire un tutoriel rédigé par un membre de ce site. Malgré tout le soin que ce membre a pu apporter au tutoriel, nous ne pouvons pas garantir que les informations contenues sur cette page sont exactes à 100%. Merci de garder cela en tête lorsque vous lirez cette page ;o)
Une des choses les plus utiles de PHP est le système d'includes, mais c'est aussi un moyen facile de hacker un site web non protégé.
Ici, nous allons voir quelques-unes de mes méthodes pour sécuriser des includes, efficacement et simplement. (Et pas long à faire en plus, vive la fainéantise !)
Sommaire du chapitre :

La méthode longue et fastidieuse

Présentation



Cette méthode consiste simplement à faire une condition vérifiant que ce qui a été donné correspond bien à une page faite pour être incluse.

Avantages



Inconvénients



Mise en application



Imaginons que je transmette mes pages avec une superglobale de cette manière :
"http://www.monsite.com/index.php?page=X" (Où X est bien sûr le nom de la page).
Pour inclure mes pages, je ferais donc de cette manière :
Code : PHP
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
<?php
if($_GET['page'] == 'page1') // ( <lien url="http://www.monsite.com/index.php?page=page1">http://www.monsite.com/index.php?page=page1</lien> )
{
   include('page1.php');
}
elseif($_GET['page'] == 'page2')
{
   include('page2.php');
}
elseif($_GET['page'] == 'page3')
{
   include('page3.php');
}
else
{
   include('accueil.php');
   /*Il faut toujours un ligne de secours.
   On n'est pas à l'abri d'une faute de frappe.*/
}
?>

Ça marche bien, tout le monde est content.
Mais maintenant il me prend l'envie de mettre une nouvelle page sur mon site. Je suis donc obligé de modifier mon code...
Puis si j'ai un super site hyper grand et tout le tintouin, ça va vite me saouler d'inclure mes 30 pages différentes de cette manière, moralité : on oublie.

Note : dans les commentaires, certains m'ont dit qu'un switch simplifierait la vie. Moi je dis le contraire : il peut paraître plus court à taper et plus clair, mais il est surtout beaucoup plus lent à l'exécution. Et comme je suis censé vous montrer comment ne pas utiliser cette méthode dans ce tuto...

La méthode courte et rapide

Présentation



En fait, ce que je vais vous présenter n'est pas une seule "chose", mais bien un ensemble de petites techniques qui formeront un tout hétérogène insécable.
Cette méthode passe par l'organisation générale du site pour pouvoir simplifier le php (et rendre le site encore moins vulnérable).

Avantages



Inconvénients



Nous pouvons commencer. :)

L'organisation

En théorie, chacun a son organisation personnelle, mais avec ma méthode il faut respecter quelques règles.

Déjà, séparer l'index du site et les fichiers à inclure ; moi je mets mes fichiers dans un sous-dossier /includes/, c'est une règle à respecter pour assurer correctement la sécurité du site, vous comprendrez par la suite.

Ensuite, une règle de nommage : je nomme mes pages comme bon me semble, mais comme j'ai certaines habitudes, je sépare souvent mes pages web en deux fichiers : la page en elle-même, et un fichier contenant les fonctions, variables et autres ; je nomme ce deuxième fichier mapage.inc.php. Le .inc est obligatoire pour appliquer les restrictions décrites plus loin : si vous ne codez pas de cette façon, c'est pas bien grave, c'est pas obligatoire.

Pour finir, le fichier de configuration, config.inc.php : ce fichier (dans mon organisation perso) contient des fonctions utilisées par toutes les pages du site ainsi que des variables et autres ; c'est un fichier sensible car beaucoup de personnes y mettent des identifiants SQL ou autres. Un nom fixe est donc (semi-)obligatoire.

En fouillant mon FTP, je sais tout de suite à quoi sert tel ou tel fichier : si c'est dans le dossier /includes/, c'est à inclure ; si le fichier ne contient pas .inc, c'est un fichier à inclure avec la superglobale ; s'il contient .inc, c'est un fichier à inclure selon la page.

Le .htaccess

Présentation



C'est une méthode d'une simplicité et d'une efficacité déconcertante : 3 lignes et c'est fait.

Avantages



Inconvénients



Mise en application



Créez un fichier .htaccess dans le dossier /includes/, et mettez-y ce texte :
Code : Apache
1
2
3
Order deny,allow
allow from 127.0.0.1
deny from all

C'est fini ! :D

Explications



Ne faisant pas dans le "Truc Et Astuces" je vais bien évidemment expliquer tout ça.
Ce modeste fichier donne l'interdiction à tout le monde d'accéder au dossier /includes/ et à tout son contenu.
Tu sais que t'es intelligent, toi ? Comment je fais pour voir la page si je peux pas y aller ?

Mais il n'y a absolument pas besoin d'y aller, vu que vous allez seulement sur l'index !
Le truc, c'est que ça n'interdit pas à tout le monde d'y accéder.

Donc, c'est inutile ?!?

Non, la seule personne qui pourra accéder au dossier sera PHP !
Explication de texte :
Code : Apache
1
Order deny,allow

Je ne suis pas vraiment sûr, mais je pense que ça définit la priorité des autorisations : en premier on interdit, après on autorise.
Code : Apache
1
allow from 127.0.0.1

Là, on autorise quelqu'un (to allow = autoriser), une IP plus précisément "127.0.0.1" ; cette ip, appelée "loopback ip", est l'ip "locale" : c'est la machine vis-à-vis d'elle-même, on pourra donc accéder au répertoire en local. PHP ne dépendant pas de cette autorisation, il pourra avoir accès au répertoire quoi qu'il arrive.
Code : Apache
1
deny from all

Là, on dit à tout le monde de dégager :D (to deny = refuser), et plus de problèmes.

La condition magique!

Là, l'organisation va commencer à servir grandement.
Nous allons faire une condition pour vérifier que la page demandée est correcte, nous avons un certain nombre de choses à vérifier.

Première condition : est-ce que quelqu'un a demandé une page?



Bah oui il faut allumer l'allumette avant la bougie :)
Donc, cette condition, je vous laisse la faire, vous devez être assez grands.
Mais je vous donne la réponse quand même.
Réfléchissez bien avant de cliquer...
Secret (cliquez pour afficher)
Code : PHP
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
<?php
if(!empty($_GET['page']))
{
   // On a demandé une page?
}
else
{
   include('includes/accueil.php');
   // Si personne ne demande de page il faut quand même en donner une...
}
?>

Vous remarquerez que je mets un !empty() et pas un isset(), si dans l'url la page n'est pas indiquée, ça sert à rien de vérifier si le rien est valide :p

Deuxième condition : Est-ce que la page existe?



Et oui, on ne peut pas inclure un fichier inexistant, désolé pour la mauvaise nouvelle.
Pour vérifier l'existence de la page, j'utilise la fonction file_exists(); qui renvoie un booléen (true (vrai) ou false (faux)). Elle attend comme paramètre le chemin du fichier à tester.
Je vous laisse mariner le temps de boire...

La réponse :
Secret (cliquez pour afficher)
Code : PHP
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
<?php
if(file_exists('includes/' . $_GET['page'] . '.php')
{
   // J'espère que vous avez pensé au dossier...
}
else
{
   include('includes/accueil.php');
}
?>


Troisième condition : La page demandée est-elle prévue à cet usage?



Et oui! Rappelez-vous des .inc tout ça...
C'est maintenant que ça sert.
Pour vérifier, je vais utiliser une regex, ça ne plaît pas à tout le monde mais vous pouvez très bien utiliser des strpos de partout si ça vous chante.
Je mets bien en gras pour vous dire que si vous voulez vérifier avec d'autres fonctions, c'est à votre bon loisir.

Voici la base de ma regex :
Code : PHP
1
<?php preg_match("//iU", $_GET['page'])) ?>

Le mode "i" (insensible à la casse) est indispensable.
Le mode "U" (ungreddy) est là pour économiser les ressources (cf : Cours de M@téo21)

Pour commencer il faut vérifier si le nom contient "inc" ou "config", si le nom le contient ça signifie que la page n'est pas destinée à être incluse par l'utilisateur, et donc que la page demandée n'est pas valide.

Code : PHP
1
<?php preg_match("/(inc|config)/iU", $_GET['page'])) ?>


Ensuite il faut vérifier si le nom contient un point.

Pourquoi?

Pour éviter ce genre de choses :
http://www.monsite.com/index.php?page= [...] especiale.php
http://www.monsite.com/index.php?page=../../config.php

Pour la première je pense que vous devez comprendre, sinon relisez le cours PHP de M@téo21
Pour la deuxième rapide explication : le "../" signifie "un dossier en arrière", si un hacker (plutôt un lamer) entre ce genre d'adresse il pourra accéder à des fichiers de configurations ou autres dont personne ne doit pouvoir voir le contenu. Pas bien donc :D

Donc, rajoutons le point dans la liste d'exclusions :
Code : PHP
1
<?php preg_match("/(\.|inc|config)/iU", $_GET['page'])) ?>

Attention de ne pas oublier d'échapper le point, c'est un métacaractère qui veut dire "tout", donc si vous ne l'échappez pas tout sera refusé, pages valides comprises


Donc on peut maintenant finir d'écrire la série de conditions :

Code : PHP
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<?php
if(!empty($_GET['page']))
{
   if(file_exists('includes/' . $_GET['page'] . '.php') AND !preg_match("/(\.|config|inc)/iU", $_GET['page']))
   {
      // On inclue la page, et si le fichier existe le .inc qui va avec
   }
   else
   {
      // On inclue la page par défaut
   }
}
else
{
   // Inclusion de la page par défaut
}
?>


Comme on dit dans le jargon très technique des informaticiens : "Ouf, c'est fini!"

Quelques trucs...

Pour finir, je vais vous donner quelques trucs à faire pour renforcer la sécurité de votre site, simples et rapides à mettre en place.

.htaccess, le retour



Là, c'est pas bien compliqué : mettre un fichier .htaccess dans les dossiers où vous ne voulez pas que l'on puisse lister les fichiers et y ajouter ce texte :
Code : Apache
1
IndexIgnore *

Le dossier et les fichiers resteront accessibles, mais il sera impossible de lister le contenu du dossier.
Attention ! Le IndexIgnore agit sur les sous-dossiers ! Si vous en mettez un à la racine de votre site, aucun dossier ne sera listable.

Mais c'est possible de faire autrement.
Au lieu de mettre le "joker" "*", on peut mettre des noms de fichiers ou autres, par exemple :
Code : Apache
1
IndexIgnore index.php *.css includes

Dans cet exemple, le dossier includes sera invisible ainsi que le fichier index.php et tous les fichiers .css.

L'index vide



Méthode simple pour empêcher le listage des fichiers, un index vide : mettez un fichier index.html dans chaque dossier avec rien dedans, ou juste un code html de base.

L'index vide 2, le retour



Ce n'est pas exactement la même chose : en fait, le truc est de faire rediriger la personne qui lit le contenu du dossier sur la racine du site, à l'aide d'un header.
Il suffit donc de placer un fichier index.php dans les dossiers et d'y rajouter ce code :
Code : PHP
1
2
3
<?php
header('Location: http://www.monsite.com/');
?>


Si quelqu'un va dans un dossier contenant ce fichier, il sera redirigé vers la racine du site.

Une dernière : l'interdiction d'accès fichier par fichier



Le principe est simple, chaque fichier est rendu illisible s'il n'est pas appelé de l'index.

La méthode



Dans le fichier qui appellera les fichiers du dossier /includes/ (index.php, donc), il faut rajouter cette ligne avant toute inclusion :
Code : PHP
1
2
3
<?php
define('IN_INDEX', TRUE);
?>

Ça définit une bête constante.

Ensuite, au tout début de chaque fichier .php du dossier include, il faut rajouter ce genre de chose :
Code : PHP
1
2
3
4
5
6
<?php
   if(!defined('IN_INDEX'))
   {
      exit('<p style="color:red;font-weight:bold;text-align:center;">Vous ne pouvez pas ouvrir ce fichier.</p>');
   }
?>


Si la constante n'est pas présente, c'est que le fichier n'a pas été inclus, donc on fait un exit (ou die(); c'est la même chose) pour arrêter l'exécution du script.

Q.C.M.

Sur quel protocole s'appliquent ces mesures de sécurité ?
Si je mets ceci dans mon .htaccess :
Code : Apache
1
IndexIgnore index.php css.* inc

Je n'aurai plus le droit de voir...


Oulà ! C'est fini !
J'ai pas vraiment envie de faire de conclusion après tout ça mais je vais me forcer.

Pour conclure :
codez proprement, soyez organisés et ne copiez pas bêtement les codes des tutos, il peut très bien y avoir des fautes (surtout quand on rédige un tuto en 4 heures sans bouger de sa chaise).

Votre site n'est pas forcement invulnérable, mais mieux protégé, et au moins c'est pas la misère pour ajouter une page ; si vous respectez les règles, tout ira bien.

A plus tard pour un nouveau tuto !
Auteur : Asibasth
Noter et commenter ce tutoriel
Imprimer ce tutoriel

Changer de design | En savoir plus | Plan du site | Politique d'accessibilité | Règles | Fil RSS | XHTML 1.0 | CSS 2.0
Édité par Simple IT SARL : Nous contacter | Revue de presse | Publicité

Y'a plus rien à lire, faut remonter maintenant !

Hébergement web - Correction de tutoriels - Créer un site
Vous souhaitez apparaître ici ? Contactez-nous.

Nombre de connectés 404 Zéros connectés | Requêtes SQL 8 requêtes | Temps de génération de la page : Total (SQL) 0.0488s (0.0202s)