Cacher le nom de fichier du contrôleur d'entrée Symfony
Publié le 23/08/2019 • Actualisé le 10/11/2024
Dans cet article nous allons voir comment cacher le nom de fichier du contrôleur d'entrée principal d'une application Symfony ("main front controller" en anglais) pour qu'il soit impossible d'accéder au site en tapant "index.php" dans l'URL. Le moins d'informations les utilisateurs (ou hackers bien sûr) auront sur l'implémentation technique de votre site, le mieux ce sera. C'est parti ! 😎
C'est l'été, cet article sera donc assez concis. En fait c'est un test que je voulais faire sur ce blog. Je voulais avoir un contrôleur spécifique pour l'environnement de production (comme avec Symfony3) et pouvoir cacher le contrôleur d'entrée principal pour que l'accès aux pages par "index.php" aboutisse à une erreur 404 et ce, sans avoir à utiliser de fichier .htaccess
ni de redirections (quand on utilise Apache comme serveur web). Ce n'est pas considéré comme une bonne pratique, utilisez à vos risques et périls !
» Publié dans "Une semaine Symfonique 660" (du 19 au 25 Août 2019).
Configuration
- PHP 8.3
- Symfony 6.4
- Apache 2.4
Introduction
Le contrôleur d'entrée principal est le fichier responsable de traiter toutes les requêtes d'une application Symfony. Quand on utilise Symfony4, c'est le fichier index.php
situé dans le répertoire "public". Par exemple quand on accède au site officiel Symfony, on remarque que les URLs suivantes sont accessibles : (ça a été corrigé depuis l'écriture de cet article qui date de 2019)
- https://symfony.com
- https://symfony.com/index.php
- https://symfony.com/blog/
- https://symfony.com/index.php/blog/
Le but ici va être d'empêcher les utilisateurs, bots ou moteurs de recherche d'accéder aux URLs via le fichier index.php
.
Création du point d'entrée spécifique de production
Ajoutez un fichier dans le répertoire "public" de votre application et nommez le avec une chaîne aléatoire. (ex: ajJoNGJix4KRMM3xwhgLXG4GUgJHhyFk.php
) Ajoutez le code suivant :
<?php
// public/ajJoNGJix4KRMM3xwhgLXG4GUgJHhyFk.php
// this is a fake name, not the one used by this website! 😁
declare(strict_types=1);
use App\Kernel;
require_once dirname(__DIR__).'/vendor/autoload_runtime.php';
return static fn (array $context) => new Kernel($context['APP_ENV'], (bool) $context['APP_DEBUG']);
Nous avons supprimé toutes les parties relatives à l'environnement de développement et aux fonctionnalités de débug pour garder le strict minimum. (il n'y a pas de différence de performance substantielle avec le contrôleur original) Nous avons toujours le fichier index.php
, dans ce projet j'ai préféré le renommer en index_dev.php
afin qu'il n'y ait pas de confusion. Mais on peut garder bien sûr le nom original.
Attention, si vous utilisez les variables d'environnement TRUSTED_PROXIES
or TRUSTED_HOSTS
vous devez garder les lignes suivantes :
if ($trustedProxies = $_SERVER['TRUSTED_PROXIES'] ?? false) {
Request::setTrustedProxies(explode(',', $trustedProxies), Request::HEADER_X_FORWARDED_ALL ^ Request::HEADER_X_FORWARDED_HOST);
}
if ($trustedHosts = $_SERVER['TRUSTED_HOSTS'] ?? false) {
Request::setTrustedHosts(explode(',', $trustedHosts));
}
Cacher le contrôleur d'entrée
Maintenant, cachons le point d'entrée. La première chose à faire est d'exclure le fichier index.php
de votre procédure de déploiement. Pour déployer le code relatif à ce blog j'utilise EasyDeploy, vous trouverez le fichier de déploiement ici). Je supprime le fichier index_dev.php
avec la fonction controllersToRemove()
. Maintenant, nous devons indiquer au serveur web d'utiliser le nouveau fichier. Par exemple si on utilise Apache :
# https://stackoverflow.com/questions/59921221/apache-how-to-handle-unknown-php-file-like-standard-urls
# configuration/vhosts/prod/www.strangebuzz.com-le-ssl.conf
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerName www.strangebuzz.com
ServerAlias strangebuzz.com
DocumentRoot /var/www-protected/strangebuzz.com/public
DirectoryIndex /ajJoNGJix4KRMM3xwhgLXG4GUgJHhyFk.php
<Directory /var/www-protected/strangebuzz.com/public>
AllowOverride All
Require all granted
# this is a fake one, again! 😁
FallbackResource /ajJoNGJix4KRMM3xwhgLXG4GUgJHhyFk.php
#FallbackResource /index.php
# 1st test to move .htaccess here
RewriteEngine On
RewriteBase /
RewriteCond %{THE_REQUEST} ^.*/index\.php
RewriteRule ^(.*)index.php$ /$1 [R=301,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /ajJoNGJix4KRMM3xwhgLXG4GUgJHhyFk.php [L]
</Directory>
ErrorDocument 404 https://www.strangebuzz.com/404
ErrorLog /var/log/apache2/strangebuzz.com_error.log
CustomLog /var/log/apache2/strangebuzz.com_access.log combined
SSLCertificateFile /etc/letsencrypt/live/strangebuzz.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/strangebuzz.com/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
# . to www
RewriteEngine on
RewriteCond %{SERVER_NAME} =strangebuzz.com
RewriteRule ^ https://www.strangebuzz.com [END,NE,R=permanent]
</VirtualHost>
</IfModule>
# Used as full snippet in templates/blog/posts/_39.html.twig
Comme vous pouvez le voir, nous avons changé la solution de repli (fallback) pour utiliser le nouveau fichier au lieu de l'ancien fichier index.php
. Et voilà ! Maintenant, maintenant quand on essaie d'accèder au site avec l'ancien nom de fichier /index.php
nous aboutissons à une erreur 404, il n'y a donc plus qu'une seule URL accessible pour cette ressource et nous sommes donc sûrs que l'URL canonique sera toujours celle sans nom de fichier php.
Bonus:
1) Il y a un article sur ce blog ou vous pourriez trouver le nom réel du contrôleur d'entrée de ce site, pouvez-vous le trouver ?
2) Pourquoi est-ce toujours indiqué index.php
?
Cliquez ici pour voir les réponses.
1) Il se trouve ici : L'antisèche intéractive de la classe Symfony Request. Le nom de fichier est retourné par la fonction getScriptName()
de l'objet / valeur (value object) Request.
2) Je triche un peu, j'ai simplement mis la valeur en dur au lieu d'utiliser le résultat de la fonction ! 😁
[
'name' => 'getScriptName',
'parameters' => '',
'type' => 'string',
//'result' => $r->getScriptName(),
'result' => 'index.php', // hide real controller name
'show' => !$refresh,
'url' => 812
],
Et voilà ! J'espère que vous avez aimé. Découvrez d'autres informations en rapport à cet article avec les liens ci-dessous. Comme toujours, retours, likes et retweets sont les bienvenus. (voir la boîte ci-dessous) À bientôt ! COil. 😊
La documentation Plus sur Stackoverflow Plus sur le web
A vous de jouer !
Ces articles vous ont été utiles ? Vous pouvez m'aider à votre tour de plusieurs manières : (cf le tweet à droite pour me contacter )
- Me remonter des erreurs ou typos.
- Me remonter des choses qui pourraient être améliorées.
- Aimez et retweetez !
- Suivez moi sur Twitter Suivez moi sur Twitter
- Inscrivez-vous au flux RSS.
- Cliquez sur les boutons Plus sur Stackoverflow pour me faire gagner des badges "annonceur" 🏅.
Merci d'avoir tenu jusque ici et à très bientôt sur Strangebuzz ! 😉
[🇫🇷] 6ème petit article de l'année. C'est un POC / test que j'ai fait sur le point d'entrée principal de mon blog. (🇬🇧 main controller)https://t.co/HQeSqWNA5O Commentaires, likes et retweets sont les bienvenus ! 😉 Objectif annuel : 6/12 (50%) #php #apache #devops #blog #blogging
— [SB] COil (@C0il) August 27, 2019