<?php
include_once $_SERVER['DOCUMENT_ROOT'] . '/include/shared-manual.inc';
$TOC = array();
$TOC_DEPRECATED = array();
$PARENTS = array();
include_once dirname(__FILE__) ."/toc/security.inc";
$setup = array (
  'home' => 
  array (
    0 => 'index.php',
    1 => 'PHP Manual',
  ),
  'head' => 
  array (
    0 => 'UTF-8',
    1 => 'fr',
  ),
  'this' => 
  array (
    0 => 'security.filesystem.php',
    1 => 'S&eacute;curit&eacute; des fichiers',
    2 => 'S&eacute;curit&eacute; des fichiers',
  ),
  'up' => 
  array (
    0 => 'security.php',
    1 => 'S&eacute;curit&eacute;',
  ),
  'prev' => 
  array (
    0 => 'security.sessions.php',
    1 => 'S&eacute;curit&eacute; des Sessions',
  ),
  'next' => 
  array (
    0 => 'security.filesystem.nullbytes.php',
    1 => 'Probl&egrave;mes li&eacute;s aux octets nuls',
  ),
  'alternatives' => 
  array (
  ),
  'source' => 
  array (
    'lang' => 'fr',
    'path' => 'security/filesystem.xml',
  ),
  'history' => 
  array (
  ),
  'extra_header_links' => 
  array (
    'rel' => 'alternate',
    'href' => '/manual/en/feeds/security.filesystem.atom',
    'type' => 'application/atom+xml',
  ),
);
$setup["toc"] = $TOC;
$setup["toc_deprecated"] = $TOC_DEPRECATED;
$setup["parents"] = $PARENTS;
manual_setup($setup);

contributors($setup);

?>
<div id="security.filesystem" class="chapter">
 <h1 class="title">Sécurité des fichiers</h1>
<h2>Sommaire</h2><ul class="chunklist chunklist_chapter"><li><a href="security.filesystem.nullbytes.php">Probl&egrave;mes li&eacute;s aux octets nuls</a></li></ul>

 <p class="simpara">
  <abbr title="PHP: Hypertext Preprocessor">PHP</abbr> est soumis aux règles de sécurité
  intrinsèques de la plupart des systèmes serveurs :
  il respecte notamment les droits des fichiers et des dossiers.
  Une attention particulière doit être portée aux
  fichiers ou dossiers qui sont accessibles à tout le monde, afin de
  s&#039;assurer qu&#039;ils ne divulguent pas d&#039;informations critiques.
 </p>
 <p class="simpara">
  Puisque <abbr title="PHP: Hypertext Preprocessor">PHP</abbr> a été fait pour permettre aux utilisateurs
  d&#039;accéder aux fichiers, il est possible de créer un
  script <abbr title="PHP: Hypertext Preprocessor">PHP</abbr> qui permet de lire des fichiers tels que <var class="filename">/etc/passwd</var>,
  de modifier les connexions ethernet, lancer des impressions de documents,
  etc. Cela implique notamment qu&#039;il faut s&#039;assurer que les fichiers
  manipulés par les scripts sont bien ceux qu&#039;il faut.
 </p>
 <p class="simpara">
  Dans le script suivant, l&#039;utilisateur indique
  qu&#039;il souhaite effacer un fichier dans son dossier racine. Nous
  supposons que <abbr title="PHP: Hypertext Preprocessor">PHP</abbr> est utilisé comme interface web pour
  gérer les fichiers, et que l&#039;utilisateur Apache est
  autorisé à effacer les fichiers dans le dossier racine des
  utilisateurs.
 </p>
 <p class="para">
  <div class="example" id="example-1">
   <p><strong>Exemple #1 Une erreur de vérification de variable conduit à un gros problème</strong></p>
   <div class="example-contents">
<div class="phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /><br /></span><span style="color: #FF8000">// Efface un fichier dans un dossier racine<br /></span><span style="color: #0000BB">$username </span><span style="color: #007700">= </span><span style="color: #0000BB">$_POST</span><span style="color: #007700">[</span><span style="color: #DD0000">'user_submitted_name'</span><span style="color: #007700">];<br /></span><span style="color: #0000BB">$userfile </span><span style="color: #007700">= </span><span style="color: #0000BB">$_POST</span><span style="color: #007700">[</span><span style="color: #DD0000">'user_submitted_filename'</span><span style="color: #007700">];<br /></span><span style="color: #0000BB">$homedir  </span><span style="color: #007700">= </span><span style="color: #DD0000">"/home/</span><span style="color: #0000BB">$username</span><span style="color: #DD0000">"</span><span style="color: #007700">;<br /><br /></span><span style="color: #0000BB">unlink</span><span style="color: #007700">(</span><span style="color: #DD0000">"</span><span style="color: #0000BB">$homedir</span><span style="color: #DD0000">/</span><span style="color: #0000BB">$userfile</span><span style="color: #DD0000">"</span><span style="color: #007700">);<br /><br />echo </span><span style="color: #DD0000">"Ce fichier a été effacé !"</span><span style="color: #007700">;<br /><br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
   </div>

  </div>
  Étant donné que le nom de l&#039;utilisateur et le nom du fichier sont fournis, des intrus peuvent
  envoyer un nom d&#039;utilisateur et un nom de fichier autres que les leurs, et effacer des
  documents dans les comptes des autres utilisateurs.
  Dans ce cas, il est préférable d&#039;utiliser une autre forme d&#039;identification.
  Il faut considérer ce qui pourrait se passer si les utilisateurs passent
  <code class="literal">../etc/</code> et <code class="literal">passwd</code> comme arguments!
  Le code serait exécuté tel que :
  <div class="example" id="example-2">
   <p><strong>Exemple #2 Une attaque du système de fichiers!</strong></p>
   <div class="example-contents">
<div class="phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /><br /></span><span style="color: #FF8000">// Efface un fichier n'importe où sur le disque dur,<br />// où l'utilisateur PHP a accès. Si PHP a un accès root :<br /></span><span style="color: #0000BB">$username </span><span style="color: #007700">= </span><span style="color: #0000BB">$_POST</span><span style="color: #007700">[</span><span style="color: #DD0000">'user_submitted_name'</span><span style="color: #007700">]; </span><span style="color: #FF8000">// "../etc"<br /></span><span style="color: #0000BB">$userfile </span><span style="color: #007700">= </span><span style="color: #0000BB">$_POST</span><span style="color: #007700">[</span><span style="color: #DD0000">'user_submitted_filename'</span><span style="color: #007700">]; </span><span style="color: #FF8000">// "passwd"<br /></span><span style="color: #0000BB">$homedir  </span><span style="color: #007700">= </span><span style="color: #DD0000">"/home/</span><span style="color: #0000BB">$username</span><span style="color: #DD0000">"</span><span style="color: #007700">; </span><span style="color: #FF8000">// "/home/../etc"<br /><br /></span><span style="color: #0000BB">unlink</span><span style="color: #007700">(</span><span style="color: #DD0000">"</span><span style="color: #0000BB">$homedir</span><span style="color: #DD0000">/</span><span style="color: #0000BB">$userfile</span><span style="color: #DD0000">"</span><span style="color: #007700">); </span><span style="color: #FF8000">// "/home/../etc/passwd"<br /><br /></span><span style="color: #007700">echo </span><span style="color: #DD0000">"Ce fichier a été effacé !"</span><span style="color: #007700">;<br /><br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
   </div>

  </div>
  Il y a deux mesures primordiales à prendre pour éviter
  ces manœuvres :
  <ul class="itemizedlist">
   <li class="listitem">
    <span class="simpara">
     Limiter les permissions de l&#039;utilisateur web <abbr title="PHP: Hypertext Preprocessor">PHP</abbr>.
    </span>
   </li>
   <li class="listitem">
    <span class="simpara">
     Vérifier toutes les variables liées aux chemins et aux fichiers
     qui sont fournis.
    </span>
   </li>
  </ul>
  Voici un script renforcé :
  <div class="example" id="example-3">
   <p><strong>Exemple #3 Une vérification renforcée</strong></p>
   <div class="example-contents">
<div class="phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /><br /></span><span style="color: #FF8000">// Efface un fichier sur le disque où l'utilisateur a le droit d'aller<br /></span><span style="color: #0000BB">$username </span><span style="color: #007700">= </span><span style="color: #0000BB">$_SERVER</span><span style="color: #007700">[</span><span style="color: #DD0000">'REMOTE_USER'</span><span style="color: #007700">]; </span><span style="color: #FF8000">// utilisation d'un mécanisme d'identification<br /></span><span style="color: #0000BB">$userfile </span><span style="color: #007700">= </span><span style="color: #0000BB">basename</span><span style="color: #007700">(</span><span style="color: #0000BB">$_POST</span><span style="color: #007700">[</span><span style="color: #DD0000">'user_submitted_filename'</span><span style="color: #007700">]);<br /></span><span style="color: #0000BB">$homedir  </span><span style="color: #007700">= </span><span style="color: #DD0000">"/home/</span><span style="color: #0000BB">$username</span><span style="color: #DD0000">"</span><span style="color: #007700">;<br /><br /></span><span style="color: #0000BB">$filepath </span><span style="color: #007700">= </span><span style="color: #DD0000">"</span><span style="color: #0000BB">$homedir</span><span style="color: #DD0000">/</span><span style="color: #0000BB">$userfile</span><span style="color: #DD0000">"</span><span style="color: #007700">;<br /><br />if (</span><span style="color: #0000BB">file_exists</span><span style="color: #007700">(</span><span style="color: #0000BB">$filepath</span><span style="color: #007700">) &amp;&amp; </span><span style="color: #0000BB">unlink</span><span style="color: #007700">(</span><span style="color: #0000BB">$filepath</span><span style="color: #007700">)) {<br />   </span><span style="color: #0000BB">$logstring </span><span style="color: #007700">= </span><span style="color: #DD0000">"</span><span style="color: #0000BB">$filepath</span><span style="color: #DD0000"> effacé\n"</span><span style="color: #007700">;<br />} else {<br />   </span><span style="color: #0000BB">$logstring </span><span style="color: #007700">= </span><span style="color: #DD0000">"Échec lors de l'effacement de </span><span style="color: #0000BB">$filepath</span><span style="color: #DD0000">\n"</span><span style="color: #007700">;<br />}<br /><br /></span><span style="color: #0000BB">$fp </span><span style="color: #007700">= </span><span style="color: #0000BB">fopen</span><span style="color: #007700">(</span><span style="color: #DD0000">"/home/logging/filedelete.log"</span><span style="color: #007700">, </span><span style="color: #DD0000">"a"</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">fwrite</span><span style="color: #007700">(</span><span style="color: #0000BB">$fp</span><span style="color: #007700">, </span><span style="color: #0000BB">$logstring</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">fclose</span><span style="color: #007700">(</span><span style="color: #0000BB">$fp</span><span style="color: #007700">);<br /><br />echo </span><span style="color: #0000BB">htmlentities</span><span style="color: #007700">(</span><span style="color: #0000BB">$logstring</span><span style="color: #007700">, </span><span style="color: #0000BB">ENT_QUOTES</span><span style="color: #007700">);<br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
   </div>

  </div>
  Cependant, même cette technique n&#039;est pas sans faille.
  Si le système d&#039;identification permet aux utilisateurs
  de créer leur propre login, et qu&#039;un utilisateur choisit
  le login <code class="literal">../etc/</code>, le système est de nouveau exposé. Pour
  cette raison, il est possible d&#039;écrire un script renforcé :
  <div class="example" id="example-4">
   <p><strong>Exemple #4 Vérification renforcée de noms de fichiers</strong></p>
   <div class="example-contents">
<div class="phpcode"><code><span style="color: #000000"><span style="color: #0000BB">&lt;?php<br /><br />$username     </span><span style="color: #007700">= </span><span style="color: #0000BB">$_SERVER</span><span style="color: #007700">[</span><span style="color: #DD0000">'REMOTE_USER'</span><span style="color: #007700">]; </span><span style="color: #FF8000">// utilisation d'un mécanisme d'identification<br /></span><span style="color: #0000BB">$userfile     </span><span style="color: #007700">= </span><span style="color: #0000BB">$_POST</span><span style="color: #007700">[</span><span style="color: #DD0000">'user_submitted_filename'</span><span style="color: #007700">];<br /></span><span style="color: #0000BB">$homedir      </span><span style="color: #007700">= </span><span style="color: #DD0000">"/home/</span><span style="color: #0000BB">$username</span><span style="color: #DD0000">"</span><span style="color: #007700">;<br /><br /></span><span style="color: #0000BB">$filepath     </span><span style="color: #007700">= </span><span style="color: #DD0000">"</span><span style="color: #0000BB">$homedir</span><span style="color: #DD0000">/</span><span style="color: #0000BB">$userfile</span><span style="color: #DD0000">"</span><span style="color: #007700">;<br /><br />if (!</span><span style="color: #0000BB">ctype_alnum</span><span style="color: #007700">(</span><span style="color: #0000BB">$username</span><span style="color: #007700">) || !</span><span style="color: #0000BB">preg_match</span><span style="color: #007700">(</span><span style="color: #DD0000">'/^(?:[a-z0-9_-]|\.(?!\.))+$/iD'</span><span style="color: #007700">, </span><span style="color: #0000BB">$userfile</span><span style="color: #007700">)) {<br />   die(</span><span style="color: #DD0000">"Mauvais utilisateur/nom de fichier"</span><span style="color: #007700">);<br />}<br /><br /></span><span style="color: #FF8000">// etc.<br /><br /></span><span style="color: #0000BB">?&gt;</span></span></code></div>
   </div>

  </div>
 </p>
 <p class="para">
  Suivant le système d&#039;exploitation, il faudra protéger
  un grand nombre de fichiers, notamment les entrées de périphériques,
  (<var class="filename">/dev/</var> ou <var class="filename">COM1</var>), les fichiers de
  configuration (fichiers <var class="filename">/etc/</var> et
  <code class="literal">.ini</code>), les lieux de stockage d&#039;informations
  (<var class="filename">/home/</var>, <var class="filename">My Documents</var>), etc.
  Pour cette raison, il est généralement plus sûr d&#039;établir une
  politique qui interdit TOUT sauf ce qui est autorisé.
 </p>
 
</div>
<?php manual_footer($setup); ?>