Files
doc-fr/security/cgi-bin.xml
2021-05-25 19:05:53 +01:00

263 lines
12 KiB
XML

<?xml version="1.0" encoding="utf-8"?>
<!-- $Revision$ -->
<!-- EN-Revision: 6a5b42e0d34c76890fd96be2b0b57516363b4c8a Maintainer: yannick Status: ready -->
<!-- Reviewed: yes Maintainer: pmartin -->
<chapter xml:id="security.cgi-bin" xmlns="http://docbook.org/ns/docbook" xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Binaires CGI</title>
<sect1 xml:id="security.cgi-bin.attacks">
<title>Faiblesses connues</title>
<simpara>
Utiliser PHP comme un exécutable <acronym>CGI</acronym> est une possibilité
pour les cas où l'on ne veut pas l'utiliser comme un module
du serveur web (comme Apache), ou bien lorsque l'on souhaite l'utiliser en
combinaison avec un gestionnaire <acronym>CGI</acronym> complémentaire, afin de
créer un environnement de script sécurisé (en utilisant
des techniques de chroot ou setuid). Une telle décision signifie
habituellement que vous installerez votre exécutable dans le
répertoire cgi-bin de votre serveur web.
<link xlink:href="&url.cert;">CERT CA-96.11</link> recommande
de ne placer aucun interpréteur à l'intérieur du répertoire
cgi-bin. Même si le programme PHP peut être utilisé comme
interpréteur indépendant, PHP a été
pensé afin de rendre impossible les attaques que ce type
d'installation rend habituellement possible :
</simpara>
<itemizedlist>
<listitem>
<simpara>
Accès au système de fichiers :
<filename role="url">http://ma.machine/cgi-bin/php?/etc/passwd</filename>
</simpara>
<simpara>
Lorsque la requête est passée dans une url, après le point
d'interrogation (?), elle est envoyée à l'interpréteur
comme une ligne de commande par l'interface CGI. Habituellement,
l'interpréteur ouvre le fichier spécifié et l'exécute.
</simpara>
<simpara>
Lorsqu'il est invoqué comme exécutable CGI, PHP refuse
d'interpréter les arguments de la ligne de commande.
</simpara>
</listitem>
<listitem>
<simpara>
Accès à n'importe quel document web sur le serveur :
<filename role="url">http://my.host/cgi-bin/php/secret/doc.html</filename>
</simpara>
<simpara>
Le "path information" dans l'url, situé juste après le nom
de l'exécutable PHP, <filename role="uri">/secret/doc.html</filename> est
utilisé par convention pour spécifier le nom du fichier
qui doit être ouvert et interprété par le programe
<acronym>CGI</acronym>. Habituellement, des directives de configuration
du serveur web (pour le serveur Apache : Action) sont utilisées pour
rediriger des requêtes vers des documents comme
<filename role="url">http://my.host/secret/script.php</filename> vers
l'interpréteur PHP. Dans une telle configuration, le serveur web
vérifie d'abord s'il a accès au répertoire
<filename role="uri">/secret</filename>, et redirige ensuite la requête vers
<filename role="url">http://my.host/cgi-bin/php/secret/script.php</filename>.
Malheureusement, si la requête est faite directement sous cette forme,
aucune vérification d'accès n'est faite par le serveur web
pour le fichier <filename role="uri">/secret/script.php</filename>,
mais uniquement pour le fichier <filename role="uri">/cgi-bin/php</filename>.
De cette manière, n'importe quel utilisateur qui peut accéder
au fichier <filename role="uri">/cgi-bin/php</filename> peut aussi
accéder à n'importe quel document protégé sur le serveur web.
</simpara>
<simpara>
Avec PHP, les options d'exécution
<link linkend="ini.cgi.force-redirect">cgi.force_redirect</link>,
<link linkend="ini.doc-root">doc_root</link> et
<link linkend="ini.user-dir">user_dir</link> peuvent être
utilisées pour prévenir ce genre d'attaque, si des restrictions
d'accès sont appliquées sur les documents du serveur. Voir
ci-dessous pour des explications plus complètes sur les
différentes combinaisons.
</simpara>
</listitem>
</itemizedlist>
</sect1>
<sect1 xml:id="security.cgi-bin.default">
<title>Cas 1 : Seuls les fichiers publics sont servis</title>
<simpara>
Si votre serveur n'a aucun document dont l'accès n'est pas restreint
par un mot de passe ou un système de vérification de l'adresse
IP, vous n'avez aucun besoin de ce type de configuration. Si votre serveur web
ne permet pas les redirections, ou si votre serveur web n'a aucun besoin de
communiquer avec le binaire PHP de manière sécurisée,
vous pouvez activer la directive INI
<link linkend="ini.cgi.force-redirect">cgi.force_redirect</link>
Vous devez tout de même vous assurer que vos scripts PHP ne dépendent pas d'un appel
de manière directe comme <filename role="php">http://my.host/cgi-bin/php/dir/script.php</filename>,
ou de manière indirecte, par redirection, <filename role="php">http://my.host/dir/script.php</filename>.
</simpara>
<simpara>
Avec Apache, les redirections peuvent être configurées en utilisant les directives "AddHandler"
et "Action" (voir ci-dessous).
</simpara>
</sect1>
<sect1 xml:id="security.cgi-bin.force-redirect">
<title>
Cas 2 : Utilisation de la directive de compilation
<literal>cgi.force_redirect</literal>
</title>
<simpara>
La directive de configuration <link
linkend="ini.cgi.force-redirect">cgi.force_redirect</link>
évite qu'un appel direct à un script PHP avec une URL comme <filename
role="php">http://my.host/cgi-bin/php/secretdir/script.php</filename> ne soit possible.
À la place, PHP analysera le fichier uniquement s'il y a eu redirection.
</simpara>
<simpara>
Habituellement, la redirection est effectuée grâce aux directives suivantes dans la
configuration du serveur Apache :
</simpara>
<programlisting role="apache-conf">
<![CDATA[
Action php-script /cgi-bin/php
AddHandler php-script .php
]]>
</programlisting>
<simpara>
Cette option a uniquement été testée avec Apache, et
compte sur Apache pour affecter la variable d'environnement non-standard
<envar>REDIRECT_STATUS</envar> pour les requêtes redirigées.
Dans le cas où votre serveur web ne supporte aucune manière d'indiquer si la requête a été
redirigée ou non, vous ne pourrez pas utiliser cette option de
compilation. Vous devrez alors utiliser une des autres méthodes
d'exploitation de la version binaire CGI de PHP, comme exposé ci-dessous.
</simpara>
</sect1>
<sect1 xml:id="security.cgi-bin.doc-root">
<title>Cas 3 : Utilisation du "doc_root" ou du "user_dir"</title>
<simpara>
Ajouter un contenu interactif, comme des scripts ou des exécutables, dans les répertoires
de documents votre serveur web, est parfois considéré comme une
pratique non-sécurisée. Si, à cause d'une erreur de configuration, le script n'est pas
exécuté mais affiché comme une page HTML classique,
il peut en résulter une fuite de propriété intellectuelle
ou d'informations liées à la sécurité, comme, typiquement, des mots de passe.
En conséquence, un bon nombre d'administrateurs
préfèrent mettre en place un répertoire
spécial pour les scripts, qui soit uniquement accessible par le biais
du binaire CGI de PHP, ce qui signifie que tous les fichiers de ce répertoire
seront interprétés et jamais affichés tels quels.
</simpara>
<simpara>
De plus, si vous ne pouvez pas utiliser la méthode
qui permet de s'assurer que les requêtes ne sont pas redirigées,
comme présentée ci-dessus, il est nécessaire de mettre
en place un répertoire de scripts "doc_root" différent du
répertoire "document root" de votre serveur web.
</simpara>
<simpara>
Pour indiquer la racine des scripts PHP, vous pouvez utiliser la directive
<link linkend="ini.doc-root">doc_root</link> dans le
<link linkend="configuration.file">fichier de configuration</link>,
ou vous pouvez affecter la variable d'environnement
<envar>PHP_DOCUMENT_ROOT</envar>. Si cette information
est renseignée, le binaire <acronym>CGI</acronym> de PHP construira
toujours le nom de fichier à ouvrir avec <parameter>doc_root</parameter>
et le "path information" de la requête, et vous serez donc sûr
qu'aucun script ne sera exécuté en dehors du répertoire
prédéfini (à l'exception du répertoire
désigné par la directive <parameter>user_dir</parameter> -
voir ci-dessous).
</simpara>
<simpara>
Une autre option possible ici est la directive
<link linkend="ini.user-dir">user_dir</link>. Lorsque cette directive n'est pas
spécifiée, seuls les fichiers contenus dans le répertoire
<parameter>doc_root</parameter> peuvent être ouverts.
Ouvrir un fichier possédant l'url
<filename role="url">http://my.host/~user/doc.php</filename> ne correspondra
pas à l'ouverture d'un fichier sous le répertoire racine de
l'utilisateur, mais à l'ouverture du fichier
<filename role="uri">~user/doc.php</filename> sous le répertoire
"doc_root" (oui, un nom de répertoire commençant par un tilde
[<literal>~</literal>]).
</simpara>
<simpara>
Si la directive "user_dir" est activée, par exemple à la valeur
<filename role="dir">public_php</filename>, une requête
du type <filename role="url">http://my.host/~user/doc.php</filename>
ouvrira un fichier appelé <filename>doc.php</filename> dans le
répertoire appelé <filename role="dir">public_php</filename>
sous le répertoire racine de l'utilisateur.
Si le répertoire racine de l'utilisateur est
<filename role="dir">/home/user</filename>, le fichier exécuté
sera <filename>/home/user/public_php/doc.php</filename>.
</simpara>
<simpara>
<parameter>user_dir</parameter> et <parameter>doc_root</parameter> sont
deux directives totalement indépendantes, et vous pouvez donc
contrôler l'accès au répertoire "document root"
séparément des répertoires "user directory".
</simpara>
</sect1>
<sect1 xml:id="security.cgi-bin.shell">
<title>
Cas 4 : Exécutable PHP à l'extérieur de l'arborescence du serveur
</title>
<para>
Une solution extrêmement sécurisée est de
mettre l'exécutable PHP à l'extérieur de l'arborescence
du serveur web. Dans le répertoire
<filename role="dir">/usr/local/bin</filename>, par exemple.
Le seul véritable inconvénient de cette méthode est que vous aurez à
rajouter une ligne comme celle-ci :
<example>
<title>Ligne d'invocation de PHP</title>
<programlisting role="cgi">
<![CDATA[
#!/usr/local/bin/php
]]>
</programlisting>
</example>
au début de chaque fichier contenant des balises PHP. Vous devrez aussi rendre les
scripts PHP exécutable. En somme, traitez le fichier
exactement comme si vous aviez un autre script écrit en Perl ou en
sh ou en un autre langage de script qui utilise <literal>#!</literal> comme
mécanisme pour lancer l'interpréteur lui-même.
</para>
<para>
Pour que l'exécutable PHP prenne en compte les variables
d'environnement <envar>PATH_INFO</envar> et
<envar>PATH_TRANSLATED</envar> correctement avec cette configuration,
la directive INI
<link linkend="ini.cgi.discard-path">cgi.discard_path</link>
doit être activé.
</para>
</sect1>
</chapter>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:t
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
indent-tabs-mode:nil
sgml-parent-document:nil
sgml-default-dtd-file:"~/.phpdoc/manual.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:nil
sgml-local-ecat-files:nil
End:
vim600: syn=xml fen fdm=syntax fdl=2 si
vim: et tw=78 syn=sgml
vi: ts=1 sw=1
-->