Se protéger contre les LFI/RFI

Plusieurs points permettent d’empêcher l’exploitation des LFI/RFI.

  • Pour les RFI :

La première et unique chose à faire, c’est de désactiver l’option « allow_url_include » et « allow_url_open » dans le fichier php.ini. Ce fichier se trouve dans le répertoire /etc/php/x.0/apache2/ (avec x le numéro de version de PHP) :

Si ces options sont désactivées alors il ne sera plus possible d’inclure d’URL et donc la partie RFI de la faille include sera patchée comme on peut le voir ci-dessous :

  • Pour les LFI :

Là c’est un peu plus compliqué. En effet on ne peut pas désactiver l’inclusion de fichiers internes puisque cela casserait pas mal de sites qui reposent sur ces fonctions. En revanche on peut limiter l’accès à certains fichier en se servant de l’option « open_basedir ».

Open_basedir est une option PHP qui permet d’indiquer à PHP quels sont les fichiers auxquels il  a accès. Avec cette option on va pouvoir dire à PHP que si quelqu’un essaye d’inclure un fichier en dehors du répertoire spécifié, eh bien PHP doit refuser l’inclusion.

Du coup si je donne ce répertoire à open_basedir :

Et que j’essaye d’accéder au fichier /etc/passwd, j’aurais une erreur :

En général ce genre de restriction d’accès est plus à faire au niveau du fichier de configuration du serveur web (que ce soit pour Apache ou Nginx) mais au cas ou, il est toujours bien de la spécifier dans le fichier de configuration de PHP.

Au niveau du code PHP, des modifications sont aussi à faire. Premièrement on va forcer l’utilisation d’une extension bien définie. En l’occurrence nous voulons que seuls les fichiers .html soient inclus. Voici comment on pourrait implémenter cette règle en PHP :

<?php
if(isset($_GET['page'])){
  include_once($_GET["page"]."html");
}
else{
  include_once("default.html");
}
?>

Seulement ce n’est pas suffisant. En plus d’imposer une extension, on pourra aussi imposer le répertoire dans lequel les fichiers à inclure sont stockés :

<?php
if(isset($_GET['page'])){
  include_once("/var/www/html".$_GET["page"]."html");
}
else{
  include_once("default.html");
}
?>

Mais encore une fois ce n’est pas suffisant car rien n’empêchera un attaquant d’utiliser les caractères « ../ » afin de se balader dans les répertoires pour inclure d’autres fichiers. Du coup il va aussi falloir filtrer les inputs en supprimant tous les caractères qui ne sont pas soit des chiffres soit des lettres. Et pour cela, on utilisera des regex :

<?php
if(isset($_GET['page']) && preg_match("/^([A-Za-z0-9_.])+$/i", $_GET["page"])){
  include_once("/var/www/html".$_GET["page"]."html");
}
else{
  include_once("default.html");
}
?>

A partir de maintenant je considère que notre application est plutôt bien sécurisée. Mais si vous voulez vraiment forcer la sécurité, rien ne vous empêche de déclarer un tableau contenant les pages incluables et de vérifier que les pages demandées font parties de ce tableau :

<?php

$pages_allowed = array("page1", "default");

if(isset($_GET['page']) && preg_match("/^([A-Za-z0-9_.])+$/i", $_GET["page"]) && in_array($_GET["page"], $pages_allowed)){
  include_once("/var/www/html".$_GET["page"]."html");
}
else{
  include_once("default.html");
}
?>

Seules les pages page1 et default pourront être incluses. Là maintenant vous pouvez être absolument sur que votre application est sécurisée contre la faille include  !