Serveur HTTP Apache Version 2.4

Ce document est un complément à la documentation de référence du module
mod_rewrite. Il décrit les concepts de base dont la
connaissance est nécessaire pour l'utilisation de
mod_rewrite. D'autres documents entrent d'avantage dans
les détails, mais celui-ci devrait aider le débutant à se mouiller les
pieds.
Introduction
Expressions rationnelles
Les bases des règles de réécriture
Drapeaux de réécriture
Conditions de réécriture
Tables de réécriture
Fichiers .htaccess
Considérations en matière de sécuritéLe module Apache mod_rewrite est un module puissant
et sophistiqué qui permet la réécriture des URLs. Grâce à lui, vous
pouvez effectuer quasiment tous les types de réécriture d'URLs dont vous
avez besoin. Il est cependant assez complexe, et peut paraître
intimidant au débutant. Certains ont aussi tendance à traiter les
règles de réécriture comme des incantations magiques, et à les utiliser
sans vraiment comprendre leur manière d'agir.
Ce document a pour ambition d'être suffisamment explicite pour permettre la compréhension, et non la copie en aveugle, de ce qui suit.
Gardez à l'esprit que de nombreuses tâches de manipulation d'URLs
courantes n'ont pas besoin de la puissance et de la complexité de
mod_rewrite. Pour les tâches simples, voir
mod_alias et la documentation sur la Mise en correspondance des URLs avec le
système de fichiers.
Enfin, avant de procéder, assurez-vous d'avoir configuré le niveau de
journalisation de mod_rewrite à un des niveaux de trace
via la directive LogLevel. Bien que
ceci risque de vous submerger sous une énorme quantité d'informations,
le débogage des problèmes avec la configuration de
mod_rewrite est à ce prix car vous verrez alors
exactement comment chaque règle est traitée.

Figure : Présentation simplifiée de la manière dont
mod_rewrite traite une requête. Voir Détails techniques pour une description complète du
traitement avec les phases, les drapeaux et le bouclage.
mod_rewrite utilise le vocabulaire des Expressions
rationnelles compatibles avec Perl à l’aide de la bibliothèque PCRE2.
Ce document n'a pas pour prétention d'être une référence détaillée des
expressions rationnelles. A cet effet, nous recommandons la documentation de
PCRE2, la page de manuel des
expressions rationnelles de Perl, et l'ouvrage Mastering
Regular Expressions, par Jeffrey Friedl (la troisième édition date
de 2006, mais la syntaxe des expressions rationnelles n'a pas vraiment
changé, et cet ouvrage reste la référence en la matière).
Dans ce document, nous avons pour but de vous fournir suffisamment de
vocabulaire des expressions rationnelles pour vous mettre le pied à
l'étrier, sans être dépassé, en espérant que les directives RewriteRule vous apparaîtront comme des
formules scientifiques, plutôt que comme des incantations magiques.
Vous trouverez dans ce qui suit le minimum à connaître pour être en
mesure d'écrire des expressions rationnelles et des règles RewriteRule. Ceci ne représente
certainement pas un vocabulaire des expressions rationnelles complet,
mais constitue un bon point de départ, et devrait vous aider à
déchiffrer les expressions rationnelles simples, et à écrire vos propres
expressions.
| Motif | Signification | Exemple |
|---|---|---|
. | Correspond à tout caractère unique | c.t correspondra à cat,
cot, cut, etc. |
+ | Répète le caractère de correspondance précédent une ou plusieurs fois | a+ correspond à a, aa,
aaa, etc. |
* | Répète le caractère de correspondance précédent zéro ou plusieurs fois | a* correspond à tout ce à quoi correspond
a+, mais correspond aussi à la chaîne vide. |
? | Rend la correspondance optionnelle. |
colou?r correspondra à color et colour. |
\ | Échappe le caractère suivant | \. correspondra à . (point) et non pas à
tout caractère unique comme expliqué ci-dessus |
^ | Appelé ancrage, correspond au début de la chaîne | ^a correspond à une chaîne qui commence par
a |
$ | L'autre ancrage, correspond à la fin de la chaîne. | a$ correspond à une chaîne qui se termine par
a. |
( ) | Regroupe plusieurs caractères en une seule entité, et conserve une correspondance à des fins d'utilisation dans une référence arrière. | (ab)+
correspond à ababab - à savoir, le +
s'applique au groupe.
Pour plus de détails sur les références arrières, voir ci-dessous. |
[ ] | Une classe de caractères - correspond à un des caractères de la classe | c[uoa]t correspond à cut,
cot ou cat. |
[^ ] | Négation de la classe de caractères - correspond à tout caractère ne faisant pas partie de la classe | c[^/]t correspond à cat ou
c=t mais pas à c/t |
Le caractère ! (Not) peut
préfixer une expression rationnelle afin d'en exprimer la négation.
Autrement dit, une chaîne ne correspondra que si elle ne correspond pas
à l'expression située après le !.
Notez que lorsqu’on utilise ! pour inverser un motif, les références arrières (par exemple $1,
$2) ne sont pas disponibles, car le motif ne correspond plus.
La règle suivante, par exemple, redirige toute requête qui ne commence
pas par /admin
RewriteRule "!^/admin" "/xyz.html" [R,L]
Vous devez vous souvenir d'une chose importante : chaque fois
que vous utilisez des parenthèses dans un Motif ou dans
un des modèles de conditions, des références arrières
sont créées en interne et peuvent être rappelées via les chaînes
$N et %N (voir ci-dessous). Ces
références sont disponibles lors de la
création de la chaîne de substitution d'une directive
RewriteRule ou de la
chaîne de test d'une directive RewriteCond.
Les captures dans les modèles de directives RewriteRule sont paradoxalement
disponibles dans toutes les directives RewriteCond qui précèdent, car
les expressions des directives RewriteRule sont évaluées avant
les conditions individuelles.
La figure 1 montre à quels endroits les références arrières sont suceptibles d'être développées, et illustre le flux des comparaisons effectuées par les règles RewriteRule et RewriteCond. Dans les chapitres suivants, nous examinerons comment utiliser ces références arrières, donc ne vous affolez pas si elles vous paraissent un peu exotiques au premier abord.

Figure 1 : Le cheminement d'une référence arrière à
travers une règle.
Dans cet exemple, une requête pour /test/1234 vers l’hôte admin.example.com serait
transformée en
/admin.foo?page=test&id=1234&host=admin.example.com,
sous réserve que %{DOCUMENT_ROOT}/test ne soit pas un fichier
existant.
Voir aussi Détails techniques pour un diagramme montrant le cheminement des références arrières avec des conditions multiples.
Une règle de réécriture RewriteRule est constituée de trois
arguments séparés par des espaces. Les arguments sont :
Le Motif est une expression
rationnelle. Dans un contexte de serveur virtuel ou de serveur global, il
est comparé au chemin d’URL %-décodé
de la requête entrante — la partie après le nom d’hôte et le port, en
excluant la chaîne de paramètres (par exemple /app/index.html).
Dans un contexte de répertoire, le motif
est comparé au chemin de la requête relatif au répertoire pour lequel la règle
est définie (avec le préfixe de répertoire supprimé — voir Réécritures par répertoire pour les
détails).
Lorsqu’une substitution a été effectuée, toute règle qui suit est comparée à la valeur substituée.
Le Motif n’est comparé qu’au chemin d’URL — à l’exclusion
des nom d’hôte, port ou chaîne de paramètres. Pour une comparaison incluant ces
derniers, utilisez une condition RewriteCond avec les variables
%{HTTP_HOST}, %{SERVER_PORT} ou
%{QUERY_STRING}, respectivement.
mod_rewrite opère exclusivement sur le chemin d’URL et les
en-têtes HTTP. Il ne peut pas inspecter le corps de la requête (par exemple, les
données POST). Si vous devez prendre des décisions de routage en fonction du
contenu du corps de la requête, traitez le problème à l’aide de la logique de
votre application ou utilisez un module tel que mod_request
associé à un filtre personnalisé.

Figure 2 : Syntaxe de la directive RewriteRule.
La chaîne de Substitution peut, quant à elle, être de trois types :
RewriteRule "^/games" "/usr/local/games/web/puzzles.html"
Ceci peut faire correspondre une requête à toute localisation voulue de
votre système de fichiers, un peu comme la directive Alias.
RewriteRule "^/games$" "/puzzles.html"
Si la directive DocumentRoot a
pour valeur /usr/local/apache2/htdocs, cette règle va faire
correspondre les requêtes pour http://example.com/games au
chemin /usr/local/apache2/htdocs/puzzles.html.
RewriteRule "^/product/view$" "http://site2.example.com/seeproduct.html" [R]
Ceci informe le client qu'il doit effectuer une nouvelle requête vers l'URL spécifiée.
/usr/) existe dans le système de fichiers, alors que ce n'est pas
le cas avec 2 (par exemple, il n'y a pas de répertoire
/bar/ au niveau de la racine du système de fichiers).La chaîne de Substitution peut aussi contenir des références arrières vers des parties du chemin d'URL entrant correspondant au Motif. Considérons ce qui suit :
RewriteRule "^/produits/(.*)/view$" "/var/web/produitsdb/$1"
La variable $1 sera remplacée par tout texte
correspondant à l'expression située entre les parenthèses dans le
Motif. Par exemple, une requête pour
http://example.com/produits/r14df/vue correspondra au
chemin /var/web/produitsdb/r14df.
S'il y a plus d'une expression entre parenthèses, elle seront
accessibles selon leur ordre d'apparition via les variables
$1, $2, $3, etc...
Le comportement d'une règle RewriteRule peut être modifié par la
présence d'un ou plusieurs drapeaux en fin de règle. Par exemple, les
conditions de correspondance d'une règle peuvent être rendues
insensibles à la casse par la présence du drapeau [NC] :
RewriteRule "^puppy.html" "petitchien.html" [NC]
Pour une liste des drapeaux disponibles, leurs significations, et des exemples, voir le document Drapeaux de réécriture.
Il est possible d'utiliser une ou plusieurs directives RewriteCond pour restreindre les types
de requêtes auxquelles devra s'appliquer la règle RewriteRule suivante. Le premier
argument est une variable décrivant une caractéristique de la requête,
le second argument est une expression rationnelle
qui doit correspondre à la variable, et un troisième argument optionnel
est une liste de drapeaux qui modifient la manière dont la
correspondance est évaluée.

Figure 3 : Syntaxe de la directive RewriteCond
Par exemple, pour renvoyer toutes les requêtes en provenance d'une certaine tranche d'adresses IP vers un autre serveur, vous pouvez utiliser :
RewriteCond "%{REMOTE_ADDR}" "^10\.2\."
RewriteRule "(.*)" "http://intranet.example.com$1"
Si vous spécifiez plus d'une directive RewriteCond, ces directives
doivent toutes être satisfaites pour que la règle RewriteRule suivante s'applique. Par exemple,
pour interdire les requêtes qui contiennent le mot "hack" dans la chaîne
de requête, sauf si elles contiennent aussi un cookie contenant le mot
"go", vous pouvez utiliser :
RewriteCond "%{QUERY_STRING}" "hack"
RewriteCond "%{HTTP_COOKIE}" "!go"
RewriteRule "." "-" [F]
Notez que le point d'exclamation indique une correspondance négative ; ainsi, la règle n'est appliquée que si le cookie ne contient pas "go"
Les correspondances dans les expressions rationnelles contenues dans
les directives RewriteCond
peuvent constituer des parties de la chaîne de Substitution
de la règle RewriteRule via
les variables %1, %2, etc... Par
exemple, ce qui suit va diriger la requête vers un répertoire différent
en fonction du nom d'hôte utilisé pour accéder au site :
RewriteCond "%{HTTP_HOST}" "(.*)"
RewriteRule "^/(.*)" "/sites/%1/$1"
Si la requête concernait http://example.com/foo/bar,
alors %1 contiendrait example.com et
$1 contiendrait foo/bar.
La directive RewriteMap
permet en quelque sorte de faire appel à une fonction externe pour
effectuer la réécriture à votre place. Tout ceci est décrit plus en
détails dans la Documentation
supplémentaire sur RewriteMap.
Il est possible d’utiliser des règles de réécriture dans un contexte de répertoire (fichiers .htaccess et sections <Directory>), mais dans ce cas, les
règles se comportent différemment — en particulier, le préfixe du répertoire est
supprimé de l’URL avant la recherche de correspondance. Voir le document Réécritures dans un contexte de
répertoire pour une explication détaillée. Notez que les sections <If> et <Location> adoptent aussi le comportement du contexte
de répertoire — voir Quels
contextes prennent en charge les règles de réécriture ?.
mod_rewrite est un outil de manipulation d’URL puissant,
mais qui dit puissance dit risque d’erreurs liées à la sécurité. Cette section
met en lumière les pièges en matière de sécurité courants à éviter lors de
la rédaction de règles de réécritures.
Si une règle RewriteRule
construit un URL de redirection en utilisant une entrée utilisateur non validée,
un attaquant pourra fabriquer un lien qui redirige les visiteurs vers un site
malveillant semblant provenir de votre domaine. Cette vulnérabilité est connue
sous le nom de redirection ouverte.
Par exemple, cette règle est dangereuse :
# DANGEREUX - permet une redirection ouverte
RewriteRule "^/redirect" "%{QUERY_STRING}" [R,L]
Un attaquant pourrait en effet utiliser
https://yoursite.com/redirect?https://evil.com pour rediriger les
utilisateurs vers un site malveillant. Assurez vous de toujours valider ou
contraindre les cibles de redirection. Si la destination doit être sur votre
propre site, assurez vous que la substitution commence par / (un
chemin relatif) plutôt que de permettre à l’utilisateur d’entrer un URL complet.
Lorsqu’on utilise la drapeau [P] (proxy),
mod_rewrite fait que le serveur
effectue une requête HTTP vers l’URL de substitution de la part du client. Si
une partie de cet URL est dérivée de l’entrée du client — références arrières,
chaînes de paramètres ou en-têtes — un attaquant pourrait faire que votre
serveur effectue des requêtes vers des services internes arbitraires ou des
hôtes externes.
Par exemple :
# DANGEREUX - l’utilisateur contrôle la cible du mandataire
RewriteCond "%{QUERY_STRING}" "target=(.+)"
RewriteRule "^/fetch" "http://%1" [P]
Un attaquant pourrait utiliser cette configuration pour tester des services réseau internes qui autrement ne seraient pas accessibles depuis l’Internet. Utilisez toujours un nom d’hôte fixe dans les cibles de mandataire et limitez les références arrières à la partie chemin seulement.
Des règles de réécriture qui associent directement des composants du chemin fournis par l’utilisateur au système de fichier ouvrent la voie à des attaques de traversée de chemin si l’entrée n’est pas correctement contrainte. Par exemple :
# DANGEREUX - permet une traversée de chemin RewriteRule "^/files/(.+)" "/var/data/$1" [L]
Une requête pour /files/../../etc/passwd pourrait accéder à des
fichiers en dehors du répertoire souhaité. Utilisez des motifs restreints dans
votre règle RewriteRule (par exemple
[a-zA-Z0-9_-]+ au lieu de .+), et utilisez les
protections intégrées d’Apache httpd (restrictions Options et <Directory>) pour une défense en profondeur.