TP06 - bpatureau/admin-2-TP GitHub Wiki

TP6 : Sécurisation du service web public

Noms des auteurs : Bastien Patureau, Guillaume Ladrière, Maxime Bongartz Date de réalisation : 24/03/25

2. Sécurisation serveur

Documentez et faites le point ici sur l'état de sécurisation de votre serveur.

2.1 Firewall

Le firewall écoute uniquement sur les ports que nous allons utiliser :

49152/tcp                  ALLOW       Anywhere
22/tcp                     ALLOW       Anywhere
53/tcp                     ALLOW       Anywhere
53/udp                     ALLOW       Anywhere
443                        ALLOW       Anywhere
49152/tcp (v6)             ALLOW       Anywhere (v6)
22/tcp (v6)                ALLOW       Anywhere (v6)
53/tcp (v6)                ALLOW       Anywhere (v6)
53/udp (v6)                ALLOW       Anywhere (v6)
443 (v6)                   ALLOW       Anywhere (v6)

Ainsi que le ports 49152 (pour s'y connecter)

2.2 docker

On vérifie le docker pour être sur qu'il contient bien les versions les plus récentes et on fait une mise a jour pour avoir les dernières versions stables.

docker images

REPOSITORY                        TAG       IMAGE ID       CREATED        SIZE
debian-web                        latest    7c9130b569fc   21 hours ago   204MB
debian-php                        latest    941a799b6c68   21 hours ago   498MB
dns-woodytoys                     dnssec    7546e86a5136   45 hours ago   39.4MB
internetsystemsconsortium/bind9   9.18      795b6052e1d6   3 days ago     39.4MB
mariadb                           11.1      6c187fecc416   6 months ago   405MB

3. Sécurisation des données

3.1. Isolation de la base de données

Ajout des deux réseau docker dmz et db_net dans le fichier docker compose :

networks:
  dmz:
    driver: bridge
  db_net:
    driver: bridge

Le server MariaDB est placé dans le réseau db_net.

  mariadb:
    container_name: db
    image: mariadb:11.1
    env_file:
      - db/root.env
      - db.env
    volumes:
      - ./db/sql/:/docker-entrypoint-initdb.d/ # MariaDB container automatically loads SQL script at startup
      - ./db/my-resolve.cnf:/etc/mysql/conf.d/my-resolve.cnf
      - ./db/data_db/:/var/lib/mysql/
    networks:
      - db_net

Le server nginx est placé dans le réseau dmz.

  nginx:
    container_name: web
    build: .
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./html/:/var/www/html/
      - ./certificate/letsencrypt:/etc/letsencrypt
    networks:
      - dmz

Et le server PHP est a la fois dans dmz et db_net.

  php:
    container_name: php
    build: php
    volumes:
      - ./html/:/var/www/html/
    env_file:
      - db.env
    networks:
      - dmz
      - db_net
  • Etablissez une procédure de validation de l'isolation de la base de données.
  1. En étant connecté au container PHP, ping la DB et ping le server Nginx. Les 2 doivent réussir.
  2. Depuis le container Nginx, ping la DB, le ping doit raté.

3.2. Configuration d'un utilisateur non privilégié

Dans le fichier sql qui est lancé dans mariaDB, on ajoute un utilisateur. Cette utilisateur appelé "wt-user" n'aura pour droit que d'utiliser SELECTsur la base de données woodytoys.

CREATE USER 'wt-user'@'tp6_php_1' IDENTIFIED BY 'wt-pwd';
GRANT SELECT ON `woodytoys`.* TO 'wt-user'@'php';

Dans notre fichier products.php, on indique que l'utilisateur et son mot de passe sont dans les variables d'environement et cet utilisateur sera wt-user.

$dbname = getenv('MARIADB_DATABASE');
$dbhost = getenv('MARIADB_HOST');
$dbuser = getenv('MARIADB_USER');
$dbpass = getenv('MARIADB_PASSWORD');
  • Proposez une procédure de validation du fait que le serveur web ne peut pas effectuer d'opération dangereuse sur la DB.

3.3. Backup de la DB

Les données extraitent de la DB sont stockées dans db/data_db. Notre container MariaDB possède un volume pour récupérer ces données.

    volumes:
      - ./db/sql/:/docker-entrypoint-initdb.d/
      - ./db/my-resolve.cnf:/etc/mysql/conf.d/my-resolve.cnf
      - ./db/data_db/:/var/lib/mysql/

3.4. Logs de la DB

Docker nous permet d'avoir accès aux logs de la DB via docker logs [nom du container].

docker logs db
2025-03-31 09:01:45+00:00 [Note] [Entrypoint]: Entrypoint script for MariaDB Server 1:11.1.6+maria~ubu2204 started.
2025-03-31 09:01:45+00:00 [Warn] [Entrypoint]: /sys/fs/cgroup///memory.pressure not writable, functionality unavailable to MariaDB
2025-03-31 09:01:45+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
2025-03-31 09:01:45+00:00 [Note] [Entrypoint]: Entrypoint script for MariaDB Server 1:11.1.6+maria~ubu2204 started.
2025-03-31 09:01:46+00:00 [Note] [Entrypoint]: MariaDB upgrade not required
error: Found option without preceding group in config file: /etc/mysql/conf.d/my-resolve.cnf at line: 1
2025-03-31  9:01:46 0 [Note] Starting MariaDB 11.1.6-MariaDB-ubu2204 source revision 80abd847daf736cf8e57e83241c2e6fed74b4ed3 server_uid 72+4ASMvYxproTQgRqIDplDA1XA= as process 1
2025-03-31  9:01:46 0 [Note] InnoDB: Compressed tables use zlib 1.2.11
2025-03-31  9:01:46 0 [Note] InnoDB: Number of transaction pools: 1
2025-03-31  9:01:46 0 [Note] InnoDB: Using crc32 + pclmulqdq instructions
2025-03-31  9:01:46 0 [Note] mariadbd: O_TMPFILE is not supported on /tmp (disabling future attempts)
2025-03-31  9:01:46 0 [Note] InnoDB: Using liburing
2025-03-31  9:01:46 0 [Note] InnoDB: Initializing buffer pool, total size = 128.000MiB, chunk size = 2.000MiB
2025-03-31  9:01:46 0 [Note] InnoDB: Completed initialization of buffer pool
2025-03-31  9:01:46 0 [Note] InnoDB: File system buffers for log disabled (block size=512 bytes)
2025-03-31  9:01:46 0 [Note] InnoDB: End of log at LSN=52404
2025-03-31  9:01:46 0 [Note] InnoDB: Opened 3 undo tablespaces
2025-03-31  9:01:46 0 [Note] InnoDB: 128 rollback segments in 3 undo tablespaces are active.
2025-03-31  9:01:46 0 [Note] InnoDB: Setting file './ibtmp1' size to 12.000MiB. Physically writing the file full; Please wait ...
2025-03-31  9:01:46 0 [Note] InnoDB: File './ibtmp1' size is now 12.000MiB.
2025-03-31  9:01:46 0 [Note] InnoDB: log sequence number 52404; transaction id 26
2025-03-31  9:01:46 0 [Note] Plugin 'FEEDBACK' is disabled.
2025-03-31  9:01:46 0 [Note] Plugin 'wsrep-provider' is disabled.
2025-03-31  9:01:46 0 [Note] InnoDB: Loading buffer pool(s) from /var/lib/mysql/ib_buffer_pool
2025-03-31  9:01:46 0 [Note] Server socket created on IP: '0.0.0.0'.
2025-03-31  9:01:46 0 [Note] Server socket created on IP: '::'.
2025-03-31  9:01:46 0 [Note] InnoDB: Buffer pool(s) load completed at 250331  9:01:46
2025-03-31  9:01:46 0 [Note] mariadbd: Event Scheduler: Loaded 0 events
2025-03-31  9:01:46 0 [Note] mariadbd: ready for connections.
Version: '11.1.6-MariaDB-ubu2204'  socket: '/run/mysqld/mysqld.sock'  port: 3306  mariadb.org binary distribution

4. Sécurisation des communications avec HTTPS

4.1. HTTPS via un certificat auto-signé

4.1.1. Génération du certificat auto-signé avec OpenSSL

En suivant les étapes de création, on arrive à ce certificat auto-signé.

bastien@vps-ba173cd9:~/admin2/tp6$ openssl x509 -noout -text -in certificate/nginx-selfsigned.crt
Certificate:
    Data:
        Version: 1 (0x0)
        Serial Number:
            7e:b0:6d:0b:e8:24:b5:94:49:8f:9c:42:b6:b2:a9:fd:5e:9a:ae:00
        Signature Algorithm: sha256WithRSAEncryption
        Issuer: C = BE, ST = Namur, L = Gembloux, O = Ephec, OU = IT, CN = ns.l1-2.ephec-ti.be., emailAddress = [email protected]
        Validity
            Not Before: Mar 23 23:00:23 2025 GMT
            Not After : Mar 23 23:00:23 2026 GMT
        Subject: C = BE, ST = Namur, L = Gembloux, O = Ephec, OU = IT, CN = ns.l1-2.ephec-ti.be., emailAddress = [email protected]
        Subject Public Key Info:
            Public Key Algorithm: rsaEncryption
                Public-Key: (4096 bit)
                Modulus:
                    00:b6:6a:95:3c:dd:41:84:19:92:d0:17:25:6c:0e:
                    f5:ae:32:65:c6:81:9e:bd:4d:b2:83:23:91:40:f6:

{: .question }

Que pense votre navigateur du certificat utilisé ? Pourquoi ? Expliquez la problématique qui est ici mise en évidence.

Le navigateur considérait le certificat comme invalide. Il n'y a aucune sécurité dans le fait d'avoir un certificat signé par soi-même. Cela ne prouve en rien la légitimité du site puisque n'importe qui peut le faire.

4.1.2. Configuration de Nginx en HTTPS pour le virtualhost www

Afin de configurer le https en nginx, il a fallu mettre en place une redirection du trafic du port 80 au port 443.

server {
    listen 80;
    server_name www.l1-2.ephec-ti.be;
    return 301 https://www.l1-2.ephec-ti.be$request_uri;
}

Réaliser le virtualhosting pour le port 443.

server {
    listen          443 ssl;
    server_name     www.l1-2.ephec-ti.be;
    index       index.html;
    root        /var/www/html/www/;
    location ~ \.php$ {
        fastcgi_pass php:9000;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

Et indiquer l'emplacement des certificats

http {
    # Format de log personnalisé incluant le virtual host
    log_format log_per_virtualhost '[$host] $remote_addr [$time_local] $status '
                                   '"$request" $body_bytes_sent';
    ssl_certificate /etc/letsencrypt/live/l1-2.ephec-ti.be/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/l1-2.ephec-ti.be/privkey.pem;

Notre site est ainsi sécurisé via HTTPS. https

4.2. Obtention d'un certificat Let's Encrypt pour le site www

On installe automatiquement certbot dans le server nginx via son Dockerfile.

FROM nginx
RUN apt-get update && apt-get install certbot python3-certbot-nginx -y
COPY nginx.conf /etc/nginx/nginx.conf
COPY html /var/www/html
EXPOSE 80 443

Le server Nginx possède un volume pour les certificat généré.

    volumes:
      - ./html/:/var/www/html/
      - ./certificate/letsencrypt:/etc/letsencrypt

4.3. Obtention manuelle d'un certificat pour le domaine

Si vous avez réalisé l'obtention d'un certificat wildcard, documentez la procédure et prouvez qu'elle fonctionne sur votre domaine (par ex. via des screenshots).