Skip to content

Créer une blacklist IP en fonction des logs serveurs récupérés dans un fichier

Objectif : rejeter les requêtes des clients qui génèrent des erreurs 404 et 500 trop fréquemment en les ajoutant à une blacklist. En général, cela signifie que le client scanne le serveur à la recherche de failles de sécurité ou fait du scraping de données. C'est un premier niveau de protection contre les attaques type DDoS ou reconnaissance.

Prérequis

Installer les outils suivants :

bash
sudo apt update && sudo apt install -y jq iptables

Vérifier l'installation :

bash
jq --version
iptables --version

Fichier de logs attendu

Caddy doit être configuré pour écrire des logs JSON dans :

/var/log/caddy/requests.json

Ce fichier doit contenir des champs .ts (timestamp) et .request.client_ip.

Créer le script monitor_blacklist.sh

bash
sudo nano /usr/local/bin/monitor_blacklist.sh

Contenu du script :

bash
#!/bin/bash

LOG_DIR="/var/log/caddy"
LOG_FILES="$LOG_DIR/requests*.json"
BLACKLIST_FILE="/etc/caddy/blacklist.txt"
FAIL2BAN_JAIL="/etc/fail2ban/jail.local"
THRESHOLD=5
DELAY=180

cleanup() {
    echo "Arrêt du script monitor_blacklist.sh"
    pkill -f "sleep"
    exit 0
}
trap cleanup SIGINT SIGTERM

# Vérification des dépendances
for cmd in iptables jq; do
    if ! command -v $cmd &>/dev/null; then
        echo "Erreur : $cmd non installé"
        exit 1
    fi
done

echo "Démarrage de la surveillance des logs..."

# Récupération dynamique des IP whitelists à partir du jail.local
readarray -t WHITELIST < <(grep -E '^ignoreip\s*=' "$FAIL2BAN_JAIL" \
    | sed 's/.*=\s*//' \
    | tr -s ' ' '\n' \
    | grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}(/[0-9]+)?')

echo "IPs en liste blanche (issues de Fail2Ban) : ${WHITELIST[*]}"

# Création de la chaîne BLOCKED si absente
if ! sudo iptables -L BLOCKED &>/dev/null; then
    sudo iptables -N BLOCKED && echo "Chaîne BLOCKED créée."
fi

# Fonction pour vérifier si une IP est dans la whitelist
is_whitelisted() {
    local ip=$1
    for entry in "${WHITELIST[@]}"; do
        if [[ "$entry" == *"/"* ]]; then
            # C'est un réseau CIDR (ex: 192.168.0.0/24)
            local network=$(echo "$entry" | cut -d'/' -f1)
            local prefix=$(echo "$network" | cut -d'.' -f1-3)
            # Si l'IP commence par le préfixe du réseau, elle est whitelistée
            if [[ "$ip" == "$prefix."* ]]; then
                return 0
            fi
        else
            # IP individuelle
            if [[ "$ip" == "$entry" ]]; then
                return 0
            fi
        fi
    done
    return 1
}

# Boucle principale
while true; do
    echo "-------------------------------------"
    echo "Analyse des logs à $(date)"

    TMP_FILE=$(mktemp)
    > "$BLACKLIST_FILE"

    # Extraction des IP à bannir
    for file in $LOG_FILES; do
        if [ -r "$file" ] && jq empty "$file" 2>/dev/null; then
            jq -r '. | [.ts, .request.client_ip] | @tsv' "$file" >> "$TMP_FILE"
        else
            echo "Fichier ignoré (illisible ou invalide JSON) : $file"
        fi
    done

    # Calcul des IP à bloquer selon le seuil
    awk -F'\t' '{ ipcount[int($1)" "$2]++ } END {
        for (key in ipcount) {
            split(key, parts, " ")
            if (ipcount[key] >= '"$THRESHOLD"') {
                print parts[2]
            }
        }
    }' "$TMP_FILE" | sort -u | while read -r ip; do
        # Filtrer avec la fonction is_whitelisted
        if ! is_whitelisted "$ip"; then
            echo "$ip"
        fi
    done > "$BLACKLIST_FILE"

    rm "$TMP_FILE"

    if [ -s "$BLACKLIST_FILE" ]; then
        echo "IPs à bloquer :"
        cat "$BLACKLIST_FILE"

        while read -r ip; do
            if [ -n "$ip" ]; then
                if ! sudo iptables -C BLOCKED -s "$ip" -j REJECT 2>/dev/null; then
                    sudo iptables -A BLOCKED -s "$ip" -j REJECT
                    echo "→ IP bannie : $ip"
                else
                    echo "→ IP déjà bannie : $ip"
                fi
            fi
        done < "$BLACKLIST_FILE"

        if ! sudo iptables -L INPUT -n | grep -q 'BLOCKED'; then
            sudo iptables -A INPUT -j BLOCKED
            echo "Chaîne BLOCKED ajoutée à INPUT."
        fi

        > "$BLACKLIST_FILE"
        echo "Fichier blacklist.txt réinitialisé."
    else
        echo "Aucune IP à blacklister."
    fi

    sleep "$DELAY"
done

Rendre le script exécutable

bash
sudo chmod +x /usr/local/bin/monitor_blacklist.sh

Configuration de la whitelist

Le script récupère automatiquement la liste des IPs à ne jamais bloquer depuis le fichier /etc/fail2ban/jail.local. Cette configuration est critique pour éviter de se bloquer soi-même.

Whitelister des IPs individuelles

bash
sudo nano /etc/fail2ban/jail.local

Ajouter ou modifier la ligne ignoreip dans la section [DEFAULT] :

ini
[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 203.0.113.50 198.51.100.25

Whitelister un réseau local complet (recommandé)

Pour éviter de bloquer des machines sur le réseau local lors de tests ou scans de sécurité, whitelist la plage complète en notation CIDR :

ini
[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 192.168.0.0/24

Explications des notations réseau :

  • 192.168.0.0/24 : toutes les IPs de 192.168.0.0 à 192.168.0.255
  • 10.0.0.0/8 : toutes les IPs de 10.0.0.0 à 10.255.255.255
  • 172.16.0.0/12 : toutes les IPs de 172.16.0.0 à 172.31.255.255

Ces plages sont des adresses privées (RFC 1918) non routables sur Internet. Les whitelister n'expose pas le serveur à des attaques externes.

Combiner réseaux et IPs individuelles

On peut combiner plusieurs types d'entrées :

ini
[DEFAULT]
ignoreip = 127.0.0.1/8 ::1 192.168.0.0/24 10.0.0.0/8 203.0.113.50

Appliquer les changements

Après modification du fichier jail.local, redémarrer les services :

bash
sudo systemctl restart fail2ban
sudo systemctl restart monitor_blacklist.service

Vérifier que la whitelist est bien chargée :

bash
sudo tail -20 /var/log/monitor_blacklist.log

On doit voir une ligne similaire à :

IPs en liste blanche (issues de Fail2Ban) : 127.0.0.1/8 192.168.0.0/24 203.0.113.50

Lancer le script manuellement (test)

bash
sudo nohup /usr/local/bin/monitor_blacklist.sh &

Vérification

Vérifier que le script tourne :

bash
ps aux | grep monitor_blacklist.sh

Lister les IP bloquées :

bash
sudo iptables -L BLOCKED -v -n

Lister les IP bloquées avec numéros de ligne :

bash
sudo iptables -L BLOCKED -v -n --line-numbers

Vérifier si une IP spécifique est bloquée :

bash
sudo iptables -L BLOCKED -v -n | grep 185.177.72.104

Lister les appels de la règle BLOCKED dans INPUT :

bash
sudo iptables -L INPUT -v -n

Gestion des IPs bloquées

Débloquer une IP spécifique

Méthode 1 - Par IP :

bash
sudo iptables -D BLOCKED -s 185.177.72.104 -j REJECT

Méthode 2 - Par numéro de ligne :

bash
# Lister avec numéros
sudo iptables -L BLOCKED -n --line-numbers

# Supprimer la ligne X (remplacer X par le numéro de la ligne)
sudo iptables -D BLOCKED X

Vider toute la chaîne BLOCKED

bash
sudo iptables -F BLOCKED

Rechercher une IP dans toutes les règles

bash
sudo iptables-save | grep 185.177.72.104

Créer un service systemd

bash
sudo nano /etc/systemd/system/monitor_blacklist.service

Contenu :

ini
[Unit]
Description=Surveillance automatique des logs HTTP et blacklisting IP
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/monitor_blacklist.sh
Restart=always
RestartSec=10
User=root
WorkingDirectory=/var/www/html
StandardOutput=append:/var/log/monitor_blacklist.log
StandardError=append:/var/log/monitor_blacklist.log

[Install]
WantedBy=multi-user.target

Activer et démarrer le service :

bash
sudo systemctl daemon-reload
sudo systemctl enable monitor_blacklist.service
sudo systemctl start monitor_blacklist.service

Vérifier son statut :

bash
sudo systemctl status monitor_blacklist.service

Vérifier les logs en temps réel :

bash
sudo tail -f /var/log/monitor_blacklist.log

Gestion des logs Caddy

Vider les logs après un scan de sécurité

Si vous effectuez un scan de sécurité (ZAP, Nessus, etc.) qui génère beaucoup de requêtes, les logs peuvent contenir un grand nombre d'erreurs qui déclenchent le blacklisting. Pour éviter d'être bloqué après le scan :

bash
# Arrêter le service de surveillance
sudo systemctl stop monitor_blacklist.service

# Vider les logs
sudo truncate -s 0 /var/log/caddy/requests*.json

# Redémarrer le service
sudo systemctl start monitor_blacklist.service

Archiver les logs avant nettoyage

bash
# Créer un répertoire d'archives
sudo mkdir -p /var/log/caddy/archives

# Archiver avec timestamp
sudo tar -czf /var/log/caddy/archives/requests-$(date +%Y%m%d-%H%M%S).tar.gz /var/log/caddy/requests*.json

# Vider les logs
sudo truncate -s 0 /var/log/caddy/requests*.json

Ajuster le seuil de détection

Le paramètre THRESHOLD dans le script définit le nombre minimum de requêtes suspectes avant blocage.

Augmenter temporairement le seuil pour un scan

bash
sudo nano /usr/local/bin/monitor_blacklist.sh

Modifier la ligne :

bash
THRESHOLD=50  # au lieu de 5

Puis redémarrer :

bash
sudo systemctl restart monitor_blacklist.service

Restaurer le seuil par défaut

Remettre THRESHOLD=5 après le scan et redémarrer le service.

Diagnostic en cas de blocage

Identifier si vous êtes bloqué

Symptômes : connexion refusée ou timeout sur les ports HTTP/HTTPS depuis une machine spécifique, mais SSH fonctionne.

Trouver votre IP

Depuis la machine bloquée :

bash
# Linux/macOS
curl -s https://api.ipify.org

# Afficher l'IP locale (réseau privé)
ip addr show  # Linux
ipconfig getifaddr en0  # macOS WiFi

Rechercher votre IP dans les règles

bash
# Rechercher dans toutes les règles iptables
sudo iptables-save | grep VOTRE_IP

# Rechercher spécifiquement dans BLOCKED
sudo iptables -L BLOCKED -n -v | grep VOTRE_IP

# Rechercher dans tous les logs
sudo grep -r "VOTRE_IP" /var/log/ /etc/ 2>/dev/null | grep -v "Binary"

Débloquer et whitelister

bash
# Débloquer
sudo iptables -D BLOCKED -s VOTRE_IP -j REJECT

# Whitelister définitivement
sudo nano /etc/fail2ban/jail.local
# Ajouter VOTRE_IP dans ignoreip

# Redémarrer
sudo systemctl restart fail2ban
sudo systemctl restart monitor_blacklist.service

Supprimer proprement le service

bash
sudo systemctl stop monitor_blacklist.service
sudo systemctl disable monitor_blacklist.service
sudo rm /etc/systemd/system/monitor_blacklist.service
sudo systemctl daemon-reload

Supprimer la chaîne BLOCKED d'iptables :

bash
# Retirer la référence dans INPUT
sudo iptables -D INPUT -j BLOCKED

# Vider la chaîne
sudo iptables -F BLOCKED

# Supprimer la chaîne
sudo iptables -X BLOCKED

Bonnes pratiques

Avant un scan de sécurité

  1. Identifier l'IP source du scan
  2. L'ajouter dans la whitelist fail2ban
  3. Redémarrer le service monitor_blacklist
  4. Vérifier dans les logs que l'IP est bien whitelistée

Après un scan de sécurité

  1. Vérifier qu'aucune IP légitime n'a été bloquée
  2. Nettoyer les logs Caddy pour éviter les faux positifs
  3. Examiner les IPs bloquées pour identifier de réelles menaces

Pour un environnement de développement

Whitelister l'intégralité du réseau local :

ini
ignoreip = 127.0.0.1/8 ::1 192.168.0.0/24 10.0.0.0/8 172.16.0.0/12

Pour un environnement de production

Whitelister uniquement les IPs fixes de confiance :

ini
ignoreip = 127.0.0.1/8 ::1 203.0.113.50 198.51.100.25

Troubleshooting

Le script ne démarre pas

Vérifier les dépendances :

bash
which jq
which iptables

Vérifier les permissions :

bash
ls -l /usr/local/bin/monitor_blacklist.sh
# Doit être exécutable : -rwxr-xr-x

La whitelist n'est pas appliquée

Vérifier que le fichier jail.local existe et contient bien ignoreip :

bash
sudo cat /etc/fail2ban/jail.local | grep ignoreip

Vérifier que la fonction is_whitelisted est présente dans le script :

bash
grep -A 10 "is_whitelisted" /usr/local/bin/monitor_blacklist.sh

Des IPs du réseau local sont toujours bloquées

Vérifier le format CIDR dans jail.local (doit inclure /24) :

bash
sudo cat /etc/fail2ban/jail.local | grep ignoreip
# Doit contenir : 192.168.0.0/24 (et non 192.168.0.0)

Vérifier les logs du service :

bash
sudo tail -50 /var/log/monitor_blacklist.log

Nettoyer les vieux logs Caddy qui contiennent des requêtes du scan :

bash
sudo truncate -s 0 /var/log/caddy/requests*.json
sudo systemctl restart monitor_blacklist.service

Ce script offre une solution autonome et robuste pour réagir automatiquement aux comportements suspects détectés dans les logs HTTP générés par Caddy.