Création d'un serveur proxy filtrant Squid

Sources de la documentation : https://elatov.github.io/2019/01/using-squid-to-proxy-ssl-sites/ et https://grumpytechie.net/2020/02/25/adding-custom-root-ca-certificates-to-debian/

Procédure validée sur Debian 11.

Présentation du projet

Nous allons réaliser un proxy interceptant les communications entre un réseau local et Internet. Dans cette documentation, il filtrera certains domaines et certaines URL, notamment les sites pour adultes et les régies publicitaires.

La machine utilisée possédera deux cartes réseau :

enp0s3
Connectée sur Internet et dont l'adresse IP est obtenue via DHCP
enp0s8
Connectée sur le réseau local et dont l'adresse IP est 10.50.0.1

Notre machine agira comme routeur pour les appareils situés sur le réseau local.

Installation des paquets

Nous allons installer Squid avec support HTTPS, iptables et les serveurs DHCP et DNS :

apt -y install squid-openssl nftables

Configuration du système

Nous allons configurer l'interface réseau enp0s8. Pour cela, nous modifions le fichier /etc/network/interfaces :

auto lo
iface lo inet loopback

auto enp0s3
iface enp0s3 inet dhcp

auto enp0s8
iface enp0s8 inet static
        address 10.50.0.1
        netmask 255.255.0.0

Appliquer ce changement :

service networking restart

Il faut permettre au serveur de transmettre les paquets reçus et d'agir comme un routeur. Pour cela, modifier la ligne suivante dans /etc/sysctl.conf :

net.ipv4.ip_forward=1

Appliquer ce changement :

sysctl -p

Nous allons créer les règles de pare-feu permettant de forcer le trafic entrant depuis l'interface enp0s8 vers le proxy en modifiant le fichier /etc/nftables.conf. Adapter selon les autres services déjà installés :

Pensez à créer une règle pour SSH si vous utilisez ce service pour configurer votre serveur. Ne vous enfermez pas dehors !
#!/usr/sbin/nft -f

flush ruleset

table inet tableinet {
	chain input {
		type filter hook input priority filter; policy drop;
		iifname lo accept
		iifname enp0s8 udp dport 67 accept
		iifname enp0s8 udp dport 53 accept
		iifname enp0s8 tcp dport 3129 accept
		iifname enp0s8 tcp dport 3130 accept
		ct state {established,related} accept
	}
	chain forward {
		type filter hook forward priority filter; policy drop;
        iifname enp0s8 tcp dport 3129 accept
		iifname enp0s8 tcp dport 3130 accept
		iifname enp0s8 tcp dport 3310 accept
		iifname enp0s8 tcp dport 389 accept
		iifname enp0s8 udp dport 53 accept
		iifname enp0s8 udp dport 67 accept
	}
	chain output {
		type filter hook output priority filter;
	}
	chain prerouting {
		type nat hook prerouting priority dstnat;
        iifname enp0s8 tcp dport 80 redirect to 3129
		iifname enp0s8 tcp dport 443 redirect to 3130
	}
	chain postrouting {
		type nat hook postrouting priority srcnat;
	}
}

Activer et redémarrer nftables :

systemctl enable nftables.service
systemctl restart nftables.service

Création du script de renouvellement des listes noires

Créer le répertoire qui contiendra les listes noires :

mkdir /etc/squid/blacklist
chown -R proxy:proxy /etc/squid/blacklist

La liste noire des sites pour adultes provient de l'Université de Toulouse 1 Capitole et la liste des régies publicitaires est hébergée sur https://pgl.yoyo.org/adservers/.

Créer le script en charge de la mise à jour des listes noires /opt/refresh-blacklist :

#!/bin/bash
wget -O /etc/blacklist/ads https://pgl.yoyo.org/adservers/serverlist.php?hostformat=nohtml&showintro=0&mimetype=plaintext
wget -O /tmp/adult.tar.gz ftp://ftp.ut-capitole.fr/pub/reseau/cache/squidguard_contrib/adult.tar.gz
cd /tmp
tar zxvf /tmp/adult.tar.gz
cp -R /tmp/adult /etc/blacklist/
rm /tmp/adult.tar.gz
service squid reload

Configurer cron pour mettre à jour les listes noires toutes les nuits à 2 heures du matin. Pour cela, exécuter la commande suivante :

crontab -e

Ajouter la configuration suivante :

0 2 * * * bash /opt/refresh-blacklist

Exécuter le script de renouvellement des listes noires :

bash /opt/refresh-blacklist

Configuration de Squid

Squid intervenant comme intermédiaire entre le client et le serveur, l'interception des communications HTTPS impose à Squid de générer les certificats SSL pour les domaines contactés.

Nous allons créer la base de données des certificats SSL de Squid :

/usr/lib/squid/security_file_certgen -c -s /var/spool/squid/ssl_db -M 4MB
chown -R proxy:proxy /var/spool/squid

Sauvegarder la configuration par défaut de Squid et effacer la configuration :

cp /etc/squid/squid.conf /etc/squid/squid.conf.bak
echo '' > /etc/squid/squid.conf

Créer la configuration de Squid pour analyser le trafic de manière transparente en bloquant les URL et les domaines renseignés dans des fichiers de listes noires. Pour cela, on édite le fichier de configuration /etc/squid/squid.conf :

http_port 3128
http_port 3129 transparent
https_port 3130 intercept ssl-bump cert=/etc/squid/cert/squid_proxyCA.pem generate-host-certificates=on
sslcrtd_program /usr/lib/squid/security_file_certgen -s /var/spool/squid/ssl_db -M 4MB
ssl_bump bump all
ssl_bump peek all
acl purge method PURGE
http_access allow purge localhost
http_access deny purge
coredump_dir /var/spool/squid
refresh_pattern ^ftp:       1440    20% 10080
refresh_pattern ^gopher:    1440 0% 1440
refresh_pattern -i (/cgi-bin/|\?) 0    0% 0
refresh_pattern (Release|Packages(.gz)*)$      0       20%     2880
refresh_pattern .       0    20% 4320
acl Safe_ports port 80       # http
acl Safe_ports port 443       # https
acl CONNECT method CONNECT
acl adult dstdomain "/etc/blacklist/adult/domains"
acl adult url_regex "/etc/blacklist/adult/urls"
acl ads dstdomain "/etc/blacklist/ads"
http_access deny !Safe_ports
http_access allow CONNECT
http_access deny manager
http_access allow localhost
http_access deny adult
http_access deny ads
http_access allow all

Créer le certificat de l'autorité de certification de Squid :

mkdir -p /etc/squid/cert/
openssl req -new -days 3650 -newkey rsa:4096 -sha256 -nodes -x509 -keyout /etc/squid/cert/squid_proxyCA.pem -out /etc/squid/cert/squid_proxyCA.pem
chown -R proxy:proxy /etc/squid/cert/
chmod 0400 /etc/squid/cert/squid_proxyCA.pem

Ajouter le certificat de l'autorité de certification de Squid dans le magasin des autorités de certifications reconnues :

mkdir -p /usr/local/share/ca-certificates
openssl x509 -inform PEM -in /etc/squid/cert/squid_proxyCA.pem -out /usr/local/share/ca-certificates/squid_proxyCA.crt
update-ca-certificates

Redémarrer le service Squid :

service squid restart

Installation du certificat de l'autorité de certification sur les clients

Sur le client, copier le fichier /usr/local/share/ca-certificates/squid_proxyCA.crt situé sur le serveur dans le répertoire /usr/local/share/ca-certificates/ du client.

Mettre à jour le magasin des certificats :

update-ca-certificates