À propos
Qu'est-ce que mbcrypt ?
mbcrypt est une extension native pour PHP, fournie sous forme de dll pour Windows et de module .so pour Linux, qui chiffre le code source d'une application PHP avant sa distribution, puis le déchiffre automatiquement et de façon transparente à l'exécution, sans jamais l'écrire en clair sur le disque.
La problématique
Lorsqu'une application PHP est livrée à un client, déployée chez un hébergeur tiers ou installée sur un serveur dont l'accès n'est pas entièrement maîtrisé, le code source reste par défaut lisible par quiconque accède au système de fichiers. Cette situation expose l'éditeur du logiciel à plusieurs risques concrets : copie ou revente non autorisée de l'application, rétro-ingénierie de la logique métier ou d'algorithmes propriétaires, altération du code pour contourner un mécanisme de licence, ou encore divulgation accidentelle de secrets (clés, identifiants, logique interne) intégrés au code source.
La réponse apportée par mbcrypt
mbcrypt répond à cette problématique en chiffrant chaque fichier PHP avec un algorithme robuste et authentifié (AES-256-GCM), ou, pour des besoins de compatibilité historique, avec un mode XOR simplifié. Le fichier chiffré demeure un fichier .php valide, déployé sans aucune modification de l'architecture applicative existante : à chaque appel, l'extension le déchiffre en mémoire, exécute le code, puis efface le contenu en clair sans jamais le persister sur le disque. Seul le détenteur du mot de passe (transmis via le code, php.ini ou une variable d'environnement) peut exécuter le fichier ainsi protégé.
Code source protégé
Le code livré n'est plus directement lisible ni modifiable par un tiers ayant accès au système de fichiers.
Déploiement inchangé
Le fichier chiffré reste un .php standard : aucune adaptation de l'hébergement ou de la structure du projet n'est nécessaire.
Chiffrement fort et authentifié
AES-256-GCM avec dérivation de clé PBKDF2 : toute altération du fichier chiffré est détectée et rejetée à l'exécution.
Avant de commencer
Prérequis pour utiliser l'extension
Cinq conditions doivent être réunies pour que mbcryptload fonctionne correctement. Elles sont identiques sous Windows et sous Linux ; seuls les noms de fichiers diffèrent.
PHP installé, version exacte
Une version comprise entre 8.0 et 8.5, en sachant s'il s'agit d'une build TS (thread-safe) ou NTS (non thread-safe) :
php -i | findstr "Thread Safety" (Windows)php -i | grep "Thread Safety" (Linux)
Le bon binaire pour cette version
Une .dll (Windows) ou une .so (Linux) compilée exactement pour la version de PHP et le mode TS/NTS visés (voir Téléchargements).
Extension activée dans php.ini
Une ligne extension=php_mbcryptload (Windows) ou extension=mbcryptload (Linux), suivie du redémarrage du service concerné (Apache, PHP-FPM) ou d'une simple relance du CLI.
OpenSSL présent à l'exécution
libcrypto-3-x64.dll (Windows) ou libcrypto.so.3 (Linux), nécessaire au mode de chiffrement recommandé, AES-256-GCM.
Runtime C (Windows uniquement)
VCRUNTIME140.dll ainsi que les composants api-ms-win-crt-*.dll (Visual C++ Redistributable), déjà présents sur la plupart des postes Windows 10/11 récents.
Vérification finale
Une fois ces cinq points réunis :
php -m | findstr mbcryptload php --ri mbcryptload
Binaires officiels
Téléchargements
Binaires précompilés pour PHP 8.0 à 8.5, disponibles en modes TS/NTS (Windows) et NTS/ZTS (Linux). Vérifiez systématiquement l'empreinte SHA-256 après téléchargement (fichier complet : CHECKSUMS.sha256.txt).
Charger une dll ou un .so qui ne correspond pas exactement à la version de PHP et au mode TS/NTS de votre installation empêche PHP de démarrer. Vérifiez systématiquement ces deux critères avant de copier un fichier.
Windows : extension mbcryptload (.dll)
Encodeur CLI Windows (pour chiffrer des fichiers, voir ci-dessous) : mbcrypt.exe (72 Ko)
Linux : extension mbcryptload (.so)
Encodeur CLI Linux (lié statiquement, sans dépendance à l'exécution) : mbcrypt (4.3 Mo)
Installation
Intégrer l'extension sous Windows
Identifier la version de PHP et le mode TS/NTS
Depuis une invite de commandes :
php -vphp -i | findstr "Thread Safety"
Copier la dll correspondante dans ext\
Exemple pour PHP 8.3 en mode TS :
copy php_mbcryptload_php83_ts.dll C:\chemin\vers\php\ext\php_mbcryptload.dll
Activer l'extension dans php.ini
extension=php_mbcryptload
Vérifier le chargement
php.exe -m | findstr mbcryptloadphp.exe --ri mbcryptload
La sortie de --ri doit afficher AES-256-GCM => enabled.
Si php -m ne liste pas mbcryptload, ou si PHP refuse de démarrer, la cause la plus fréquente est un mauvais choix TS/NTS ou une version de PHP qui ne correspond pas exactement à la dll utilisée : revoir l'étape 1.
Installation
Intégrer l'extension sous Linux
Identifier la version de PHP, le mode et le dossier d'extensions
php -vphp -i | grep "Thread Safety"php -i | grep ^extension_dir
Copier la .so correspondante
Exemple pour PHP 8.3 en mode NTS :
sudo cp mbcryptload_php83_nts.so "$(php -i | grep ^extension_dir | awk '{print $3}')/mbcryptload.so"
Activer l'extension dans php.ini (CLI et FPM)
echo "extension=mbcryptload" | sudo tee /etc/php/8.3/cli/conf.d/20-mbcryptload.iniecho "extension=mbcryptload" | sudo tee /etc/php/8.3/fpm/conf.d/20-mbcryptload.inisudo systemctl restart php8.3-fpm
Vérifier le chargement
php -m | grep mbcryptloadphp --ri mbcryptload
Un fichier .so compilé pour une version et un mode donnés fonctionne sur toute distribution dont la glibc est égale ou plus récente que celle utilisée à la compilation. Il ne s'agit donc jamais d'une question de distribution (Ubuntu, Debian, RHEL...) en tant que telle, mais uniquement d'architecture CPU, de version de PHP, de mode et de version de glibc.
Utilisation
Chiffrer un fichier PHP
Le chiffrement s'effectue hors ligne, une seule fois, à l'aide de l'encodeur en ligne de commande (mbcrypt.exe / mbcrypt), jamais à l'exécution.
# Mode XOR historique (sans mot de passe, compatibilité V2 uniquement) mbcrypt -o output.php source.php # Mode AES-256-GCM (recommandé) mbcrypt -p "mon-mot-de-passe" -o output.php source.php # Dossier entier, traitement récursif mbcrypt -r -p "mon-mot-de-passe" -o app_chiffree/ app_source/
XOR ou AES-256-GCM ?
- Chiffrement simple et très rapide
- Aucun mot de passe requis
- Facile à casser, ne protège pas un secret réellement sensible
- Conservé uniquement pour la compatibilité avec la V2
- Chiffrement fort, standard de l'industrie
- Mot de passe requis (clé dérivée via PBKDF2)
- Authentifié : toute altération est détectée
- Mode recommandé pour tout usage réel
Le fichier chiffré demeure un .php valide, à déployer tel quel : aucune extension de fichier ni structure de dossier à modifier côté application.
Configuration
Fournir le mot de passe à l'exécution
Dans le code PHP (le plus flexible, par requête)
mbcryptload_set_password("mon-mot-de-passe");
require "module_chiffre.php";
Directive php.ini (recommandée : appel direct, aucun code requis)
mbcryptload.password = "mon-mot-de-passe"
PHP_INI_SYSTEM : non surchargeable par ini_set() ou .htaccess.
Variable d'environnement (pratique pour Apache / PHP-FPM)
MBCRYPTLOAD_PASSWORD=mon-mot-de-passe
Visible via phpinfo() et les outils système : la moins sûre des trois méthodes.
Ordre de priorité si plusieurs méthodes sont actives simultanément : 1 > 2 > 3
Tests
Tester que tout fonctionne
L'extension est bien chargée
php -m | findstr mbcryptload (Windows) / php -m | grep mbcryptload (Linux)
Le mode AES-256-GCM est actif
php --ri mbcryptload
Doit afficher AES-256-GCM => enabled. En son absence, l'extension n'a pas été compilée avec le support OpenSSL : seul le mode XOR sera disponible.
Chiffrer puis déchiffrer un fichier de test
mbcrypt -p "test-2026" -o demo.encrypted.php demo.php
php -r 'mbcryptload_set_password("test-2026"); require "demo.encrypted.php";'
Le script doit s'exécuter normalement, comme s'il n'avait jamais été chiffré.
Vérifier le rejet d'un mauvais mot de passe
Avec un mot de passe incorrect, le require doit échouer explicitement (erreur d'authentification GCM), et ne jamais exécuter silencieusement un contenu corrompu ou vide.
Référence
Format du fichier chiffré (V3) et sécurité
Les champs colorés (sel, nonce, tag d'authentification) ne sont présents qu'en mode AES-256-GCM.
PBKDF2-SHA256, 100 000 itérations
Dérive une clé de 32 octets à partir du mot de passe, rendant une attaque par force brute extrêmement lente.
Sel aléatoire par fichier
Un même mot de passe produit une clé différente pour chaque fichier chiffré.
GCM = chiffrement authentifié
Un fichier corrompu ou modifié échoue explicitement au déchiffrement : jamais de résultat erroné silencieusement accepté.
Jamais écrit en clair sur disque
Le déchiffrement a lieu en mémoire, le temps de l'exécution, puis son résultat disparaît.
Production
Mettre à jour un binaire déjà en production
Remplacer un mbcryptload.so déjà chargé par des workers PHP-FPM actifs n'est jamais une simple copie de fichier : c'est une opération sensible au timing, à traiter avec la même rigueur qu'une migration de base de données en production.
Ne jamais faire cp nouveau.so /chemin/mbcryptload.so directement sur un système où php-fpm tourne. Un cp en place n'est pas atomique : pendant la fraction de seconde où le fichier est en cours d'écriture, un worker qui redémarre (pm = dynamic) peut charger un binaire tronqué et faire planter en boucle tous les workers du pool.
Option A : copie + mv atomique (recommandée, zéro downtime)
mv sur un même système de fichiers repose sur l'appel système rename(), atomique par construction : un worker qui charge l'extension au même instant voit soit l'ancien fichier complet, soit le nouveau, jamais un état intermédiaire.
EXT_DIR=$(php -i | grep ^extension_dir | awk '{print $3}')
sudo cp mbcryptload_nouveau.so "$EXT_DIR/.mbcryptload.so.new"
sudo mv "$EXT_DIR/.mbcryptload.so.new" "$EXT_DIR/mbcryptload.so"
Les workers déjà démarrés gardent l'ancien binaire en mémoire (le fichier reste ouvert) ; seuls les prochains workers respawnés chargeront le nouveau. Pour forcer une bascule immédiate et homogène, enchaîner avec un redémarrage classique du pool une fois tous les fichiers remplacés.
Option B : arrêt du pool avant remplacement (plus simple, downtime bref)
sudo systemctl stop php8.3-fpm
sudo cp mbcryptload_nouveau.so "$(php -i | grep ^extension_dir | awk '{print $3}')/mbcryptload.so"
sudo systemctl start php8.3-fpm
Downtime de l'ordre de la seconde le temps du stop/start, à réserver aux fenêtres hors heures de pointe si le pool est partagé avec d'autres sites.
Vérification post-déploiement, dans tous les cas
sudo systemctl status php8.3-fpm --no-pager # active (running), pas de boucle de restart
php8.3 -m | grep mbcryptload # extension chargée
sudo tail -20 /var/log/php8.3-fpm.log # pas de "Terminating" en boucle
curl -sk -o /dev/null -w "%{http_code}\n" https://votre-domaine/
Production
Désactivation d'urgence (rollback)
Si un problème apparaît après une mise à jour, couper le chargement de l'extension est plus rapide et plus sûr qu'un rollback de binaire : le fichier .so lui-même n'est pas touché, seul son chargement au démarrage est désactivé.
# Par version PHP concernée (cli et fpm) sudo mv /etc/php/8.3/fpm/conf.d/20-mbcryptload.ini /etc/php/8.3/fpm/conf.d/20-mbcryptload.ini.disabled sudo mv /etc/php/8.3/cli/conf.d/20-mbcryptload.ini /etc/php/8.3/cli/conf.d/20-mbcryptload.ini.disabled sudo systemctl restart php8.3-fpm
Réactivation : renommer .ini.disabled en .ini, puis redémarrer le pool FPM concerné. Aucune recompilation ni redéploiement de binaire n'est nécessaire pour revenir en arrière.
Production
Chiffrer une application déjà en production
Marche à suivre pour protéger le code source d'une application déjà déployée, sans interruption de service, avec un filet de sécurité à chaque étape.
Sauvegarde complète, avec vérification d'intégrité
Archiver l'application entière avant toute modification, puis vérifier que le nombre de fichiers dans l'archive correspond exactement au nombre de fichiers sur disque. Cette sauvegarde devient la seule copie en clair du code une fois le chiffrement effectué : la conserver hors du DocumentRoot.
Test sur un fichier isolé avant le traitement en masse
Chiffrer une copie d'un seul fichier, vérifier la présence du tag MB_ENC_V3 en tête de fichier, puis confirmer qu'il s'exécute correctement avec le mot de passe attendu, avant de lancer quoi que ce soit sur l'ensemble du code.
Chiffrement en place, fichier par fichier, toujours de façon atomique
Ne jamais écraser directement un fichier source par la commande de chiffrement elle-même. Chiffrer vers un fichier temporaire dans le même dossier, restaurer explicitement propriétaire et permissions d'origine (un mv ne les préserve pas), puis mv atomique par-dessus l'original (même principe que pour la mise à jour d'un .so ci-dessus).
MBCRYPT="/chemin/vers/mbcrypt"
PASSWORD="mot-de-passe"
find app/ routes/ -name "*.php" -print0 | while IFS= read -r -d '' f; do
owner=$(stat -c '%U:%G' "$f"); mode=$(stat -c '%a' "$f")
tmp="$(dirname "$f")/.$(basename "$f").tmp"
"$MBCRYPT" -p "$PASSWORD" -o "$tmp" "$f" || { echo "ECHEC: $f"; rm -f "$tmp"; continue; }
head -c9 "$tmp" | grep -q "MB_ENC_V3" || { echo "TAG INVALIDE: $f"; rm -f "$tmp"; continue; }
chown "$owner" "$tmp"; chmod "$mode" "$tmp"
mv "$tmp" "$f"
done
Un fichier déjà chiffré est ignoré automatiquement par mbcrypt (protection anti double-chiffrement intégrée) : relancer le script sur un dossier partiellement traité ne présente aucun risque.
Vider les caches applicatifs et recharger
Vider tout cache de configuration/routes/vues de l'application, puis redémarrer le pool PHP-FPM concerné : indispensable si l'opcache tourne avec validate_timestamps désactivé en production.
Vérification, dans l'ordre
Tag MB_ENC_V3 présent sur tous les fichiers ciblés, puis une commande qui charge réellement les classes chiffrées (pas seulement une vérification de syntaxe), puis le site réel en HTTP, puis tout worker en file d'attente redémarré à froid, pour prouver le rechargement depuis le disque et pas seulement la mémoire d'un process déjà démarré avant le chiffrement.
Avec un superviseur de process (type Supervisor), le nom adressable complet d'un worker est généralement <groupe>:<groupe>_00, pas le nom du groupe seul : une commande de redémarrage sur le mauvais nom échoue souvent silencieusement, sans rien redémarrer.
Une question ?
Nous contacter à propos de mbcrypt
Question technique, besoin d'une version personnalisée ou d'un accompagnement à l'intégration, écrivez-nous.