default_favicon

J’avais déjà fait un article sur ça il y a longtemps, mais là aussi il semble qu’elle ne soit plus au goût du jour.

Après moult tests et quelques surprises, je mets ici quelques snippets de code, pour mémo, surtout pour moi.

Notes :

  • Dans ce qui suit, si vous voyez un example.com, il faut remplacer ça par votre site à vous ;
  • Ceci est adapté à mon site, mes préférences en termes d’URL.
  • Vérifiez que votre serveur supporte les redirections et le fichier .htaccess.

Notes 2 :
Selon votre fichier et les règles qui s’y trouvent déjà, il peut être nécessaire d’y ajouter (une fois) les instructions suivantes :

RewriteEngine on
RewriteBase /

Je ne les fais pas figurer partout ci-dessous.

Forcer la redirection HTTPS

Les navigateurs le font tout seuls parfois, mais il vaut mieux l’ajouter :

## Force HTTPS
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301]

Supprimer le « www », au début du nom du site

Certains préfèrent le conserver, d’autres non. Dans tous les cas, il est préférable d’avoir un choix et de forcer la redirection de l’une des URL vers l’autre. C’est plus propre et c’est aussi mieux pour le référencement d’avoir une seule URL pour chaque ressource :

## Removes www.
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
RewriteRule ^(.*)$ https://%1%{REQUEST_URI} [R=301]

Supprimer les slashes redondants

J’ai mis du temps à trouver un code qui fonctionne quelle que soit la position des doubles-slashs. Généralement les forums en proposaient plusieurs selon que le slash soit au début, à la fin ou au milieu de l’URL.

## Removes multiple consecutive slashes anywhere in URL
RewriteCond %{THE_REQUEST} \s[^?]*//
RewriteRule ^.*$ /$0 [R=301,NE]

Maintenant, les urls suivantes :

  • exemple.com///dossier/fichier ;
  • exemple.com/dossier///fichier ;
  • exemple.com/dossier/// ;
  • exemple.com////dossier///fichier

Sont toutes réécrites en :

  • exemple.com/dossier/fichier

Supprimer le code derrière le chemin d’un script

## Rewrite ^*.php/*$ to *.php$ (removes anything after a "*.php/")
RewriteCond %{REQUEST_URI} ^(.*)\.php/(.*)$
RewriteRule . %1.php [R=301]

Celui-là est plus compliqué.
Quand on appelle un fichier fichier.php, on en exécute le contenu. Si l’on l’appelle avec un paramètre fichier.php?parametre, c’est toujours le même fichier qui est exécuté, mais maintenant l’exécution tient compte de la valeur du paramètre.

Dans le cas suivant par contre, il y a possibilité de problèmes : fichier.php/.
Le fichier est appelé (et donc exécuté), mais il est traité comme un dossier (car il est suivi d’un slash et non d’un point d’interrogation), et avec lui la notion de profondeur de l’arborescence, etc.
C’est un problème assez sévère et je préfère l’éviter.

J’y vais donc assez lourdement : quand je vois un fichier .php qui est directement suivi d’un slash, on vire tout ce qui suit le slash, incluant ce dernier.

Les urls suivantes :

  • exemple.com/fichier.php ;
  • exemple.com/fichier.php/ ;
  • exemple.com/fichier.php/blabla/autreblabla ;

Sont toutes réécrites en :

  • exemple.com/fichier.php

Notez que ça ne visera que le script exécuté. Rien n’empêche en effet d’avoir la chaîne « .php » suivi d’un slash dans un paramètre d’un autre fichier php (celui exécuté).
Cette URL ne sera pas modifiée, par exemple : exemple.com/fichier.php?parametre=fichier.php/bla/bla

Supprimer le « index.php » à la fin des URL

## Rewrites "/index.php" to "/"
RewriteCond %{REQUEST_URI} ^(.*)/index\.php$ [NC]
RewriteRule . %1 [R=301,L]

Quand on affiche un dossier sur un site, comme example.com/folder/, le « index.php » ou « index.html » qu’il contient est implicitement affiché. C’est la page par défaut. Le demander de façon explicite est donc généralement inutile.

Afin d’éviter d’avoir des URL redondantes, je préfère ne conserver que les URL sans le « index.php ». Les éventuels paramètres, eux, sont maintenus.

Pour résumer

Avec tout ça, toutes les URL suivantes :

  • http://lehollandaisvolant.net/tuto/ (https)
  • http://www.lehollandaisvolant.net/tuto/ (https ; www)
  • https://lehollandaisvolant.net/tuto/ (url OK)
  • https://lehollandaisvolant.net//tuto/ (double slash après le TLD)
  • https://lehollandaisvolant.net/tuto/// (double slash à la fin)
  • https://lehollandaisvolant.net/tuto/index.php (index.php)
  • https://lehollandaisvolant.net/tuto/index.php/ (index.php + slash)
  • https://lehollandaisvolant.net/tuto/index.php/folder/ (index.php + slash + faux-dossier)
  • http://www.lehollandaisvolant.net//////tuto/index.php//dossier/sousdossier/foo/ (tout ce qui précède)

Renvoient toutes sur :

  • https://lehollandaisvolant.net/tuto/

Petite note sur les cascades de fichers .htaccess

On peut mettre un fichier .htaccess dans chaque dossier et leurs sous-dossiers si l’on veut, et les directives seront appliquées à tous les fichiers inclus dans le dossier, y compris leurs sous-dossiers.

Par contre, mettre un RewriteEngine on dans un des sous-dossiers pourra avoir pour effet d’annuler les directives des fichiers situées dans les dossiers parents. C’était le cas chez moi récement, même si je n’ai pas souvenir d’un tel comportement lors de la mise en place de ces fichiers.
Il est possible que ça vienne de la configuration du serveur.

12 commentaires

gravatar
seb a dit :

Question con: Il y a un ordre à respecter ou on peut mettre tout ça dans n'importe quel ordre dans le fichier?

gravatar
oliverpool a dit :

On peut utiliser "%{HTTP_HOST}" pour éviter de devoir encoder en dur le nom de domaine.

Pour le HTTPS, j'utilise le snippet suivant (pour être "pro" il faudrait aussi renvoyer des headers HSTS):


    # instead of port check, check if HTTPS is on
    RewriteCond %{HTTPS} !=on
    # don't redirect to https if we are behind some reverse proxy
    RewriteCond %{HTTP:X-Forwarded-Proto} !https
    # 301: permanent redirect
    RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
gravatar
Le Hollandais Volant a dit :

@seb : a priori oui.
Perso j’aurais quand-même tendance à mettre en priorité les directives « de sécurité », comme le forçage HTTPS, avant tout le reste.

@oliverpool : super, merci !
Oui, le HTTP_HOST sont dans certaines mais pas partout, je vais changer ça. Par contre le HTTP_HOST ne contient que le nom de domaine ou également le WWW ?

Si c’est juste le NDD, je dois mettre :

## Removes www.
RewriteBase /
RewriteCond %{HTTP_HOST} ^www.%{HTTP_HOST} [NC]
RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301]

D’ailleurs, autre question : tout le monde met un « [L] » (« last ») à la fin de chaque rewrite-rule. Pourquoi ? Pourquoi pas seulement à la fin de la dernière ?

gravatar
Breizh a dit :

Quand tu mets un L c’est que tu estimes que quoiqu’il arrive aucune des règles suivantes ne devra s’appliquer. Ça évite de les interpréter pour rien, les boucles involontaires de Rewrite, et autres délires du genre. En gros il vaut mieux le mettre partout sauf à la fin de celles qui ne doivent pas empêcher les suivantes de se faire si matchées.

gravatar
Strahd+Ivarius a dit :

pour l'usage du [L], il faut lire la documentation, bien entendu...

RewriteRule Flags - L

Les pôvres qui mettent des [L] sur chaque RewriteRule doivent s'arracher les cheveux quand ils enchaînent plusieurs règles devant s'exécuter à la suite et qu'ils constatent que seulement une partie est prise en compte...

gravatar
Le Hollandais Volant a dit :

@Strahd+Ivarius : Ben j’ai lu la doc, et j’interprète exactement comme toi : j’ai actuellement plusieurs réécritures d’URL à la suite (celles de l’article notamment) et toutes doivent s’appliquer, donc je ne vois pas l’intérêt de mettre le L partout.

Récemment j’ai constaté par hasard que les règles ne marchaient plus. J’ai vu ce L (qui a toujours été là).

En cherchant sur les forums / stackoverflow, ce « L » est systématiquement là, partout, y compris sur les postes qui mettent plusieurs réécritures.

@Breizh : ben justement : toutes mes règles doivent être testées et appliquées si besoin.
Par exemple si l’on tape « http://www.lehollandaisvolant.net », je veux :
1. qu’il me renvoie sur HTTPS
2. qu’il me vire le www.

Si l’on avait tapé « https://www.lehollandaisvolant.net », la première règle sera inutile, mais ça ne peux pas le savoir à l’avance, et de toute façon ça sera exclu de la condition « si ( non-https ) », donc bon.

Du coup je mets le L seulement à la fin, dans la dernière réécriture.

Pas sûr que ça soit utile, mais j’ai pas vraiment d’exemples où cette option serait réellement utile, en fait. Si y a des boucles infinies, c’est qu’il y a un problème de logique dans le programme. Le L ne changera pas ça, il limitera juste les dégats.

gravatar
oliverpool a dit :

@Le Hollandais Volant :
`HTTP_HOST` contient le nom de domaine complet (fqdn), du coup ta proposition ne fonctionnera probablement pas.

Pour rajouter www dans tous les cas: (copié de https://stackoverflow.com/a/11629839/3207406)


# if the FQDN does not start with "www."
# "!" is used for negation, "^" is to ensure that "www." is at the beginning "\." ensure that it is a dot 
# (without the "\" a "." matches anything)
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^(.*)$ https://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

Pour enlever le www, ça nécessite un peu plus de magie et de regex-matching (copié de https://stackoverflow.com/a/36978519/3207406).


# if the FQDN starts with www
# "(.+)" captures everything after the "."
RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
# "%1" contains the part which was captured previously
RewriteRule ^(.*)$ https://%1%{REQUEST_URI} [R=301,L]

Un outils très pratique existe pour tester quelques règles de redirection apache: https://htaccess.madewithlove.be/ (il n'est pas exempt de bug, mais est beaucoup plus rapide que de tester à la main9.

gravatar
Le Hollandais Volant a dit :

@oliverpool : Merci (bis), pour ces réponses et ces recherches.

Je testerais ça.
Ça serait quand-même mieux d’avoir des commandes prêtes à l’emploi sans qu’un novice n’ait à changer quoi que ce soit (mois de risques d’erreurs).

Pour les regex, ça va encore : celles-ci sont légères et les commentaires aident bien.

gravatar
Galex a dit :

Tout ça ne sert à rien ou alors tout juste à cacher des détails techniques aux utilisateurs, qui feraient des bizarreries avec les URL on ne sait comment… de les prendre pour des cons… Enfin j’imagine que tous ces détails de canonicalisation (les index.php, les slashs redondants, le www, le https clône) étant pas normalisés ça fait chier le moteur de recherche qui peut pas unifier ça lui-même… ça serait bien si yavait un truc genre, un cache, pour lui montrer que 2 pages sont les mêmes… et qu’il se fiait davantage aux liens internes qu’externes…

J’aime trop la simplicité pour apprécier cet article :c

Bonne journée en tout cas ! les .htaccess c’est cool ! mangez-en !

gravatar
Le Hollandais Volant a dit :

@Galex : on peut s’en passer, c’est vrai, après j’aime bien que mes URL soient propres et unifiées : tous avec le même schéma.
Certains préfèrent le WWW, d’autres non… C’est personnel, mais pour ma part je veux qu’un choix clair soit fait, pas avoir les deux possibilités.

Je hurle quand je vois les logs pleins de « http://lehollandaisvolant.net/////tuto///index.php », parce qu’un crawler a trouvé une url mal foutue quelque part et l’a partagée… C’est un peu comme la prolifération des virus : à la fin t’as des variants partout et c’est chiant à maintenir. Au moins en envoyant tout le monde sur la même URL ça maintient le site propre (et ouais, je suis maniaque sur ça :p).

Mais chacun sa vision des choses.

gravatar
Réchèr a dit :

Bonjour,

Si je peux me permettre, une url de ce type : "exemple.com/fichier.php?parametre=fichier.php/bla/bla" est souvent symptômatique d'un site web ayant une vulnérabilité. Et le fait de l'avoir indiqué en exemple dans cet article, sans aucune explication sur la sécurité informatique, nuit un peu à la qualité du propos.

Les personnes qui ne réaliseraient pas en quoi ce genre d'url pose problème peuvent aller voir ici : https://www.neuralegion.com/blog/local-file-inclusion-lfi/ et ici : https://fr.wikipedia.org/wiki/Remote_File_Inclusion

Il est possible qu'il n'y ait pas de faille, par exemple avec un filtrage par liste blanche (si le paramètre est différent de "fichier.php" ou "autre_fichier.php", le serveur ne fait rien). Mais ça fait quand même pas très sérieux.

Auprès des personnes qui s'y connaissent un peu en sécurité, un webmaster a beaucoup plus de chances de passer pour un gros tagazou avec une url comme ceci : "exemple.com/fichier.php?parametre=fichier.php" plutôt qu'avec une url comme ceci : "wwwwww.exemple.com///url////mal//fichue//index.HtMl".

Mais sinon, merci pour cet article et ce blog en général, il est souvent très instructif !

gravatar
Le Hollandais Volant a dit :

@Réchèr : En effet, ces URL posent problème.
Je ne les utilise pas, rassures-toi, c’est juste que j’ai trouvé ce genre d’URL dans mes logs et à la pelle.

Un bot doit à mon avis fouiller tout le site (et tout le web) à la recherche de ce genre d’URL et en exploiter les failles, en cherchant par exemple « https://example.com/fichier.php?parametre=fichier.php/../../../../etc/passwd ».

Ou alors une URL mal fichue (par simple erreur) dans une de mes pages et de lien en lien, tout le site finit scrawlable sous des URL pourries.

Quoi qu’il en soit, désormais je corrige ces URL via htaccess ce qui permet de remettre tout le monde sur les rails.

Les commentaires sont fermés pour cet article