Sécuriser Nextcloud sur Raspberry Pi avec un pare-feu

image pare-feu

Cet article est un complément au guide d’installation de Nextcloud sur Raspberry Pi.

Il a pour but de mieux sécuriser Nextcloud sur Raspberry Pi avec un pare-feu.

 

En effet, pour fonctionner le serveur Nextcloud doit être ouvert sur l’extérieur. De même, nous avons configuré le Raspberry Pi en mode “headless”, c’est à dire sans écran ni clavier. Pour communiquer avec le Pi depuis un ordinateur, nous avons ouvert un port SSH.

Nous avons pour le moment trois protections pour nous protéger des attaques extérieures :

  • le routeur de notre réseau (la box) sur lequel nous avons ouvert uniquement trois ports (80 – http et 443 -https pour Nextcloud et le 22 pour le SSH),
  • les mots de passe du système d’exploitation Raspbian et de Nextcloud
  • le logiciel fail2ban qui va nous protéger contre les “attaques par force brute”, c’est à dire la tentative d’un intrus de découvrir les mots de passe par des essais multiples.

 

Le pare-feu va nous apporter une protection supplémentaire :

  • en rejetant les connexions suspicieuses,
  • en évitant certaines attaques par déni de services (saturation du réseau pour l’empêcher de fonctionner voire le mettre hors service et exploiter une faille),
  • en limitant les portes d’entrée et de sortie (le routeur ne protège pas les connexions sortantes).

 

Première rencontre avec iptables

Le système d’exploitation Raspbian est pré-installé avec un pare-feu (netfilter) avec lequel on communique par une interface appelée iptables.

Nous allons vérifier dans un premier temps la configuration de base de ce pare-feu avec la commande iptables -L sur le Raspberry :

lambda_user@myweb:~ $ sudo iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination
fail2ban-pam-generic  tcp  --  anywhere             anywhere
fail2ban-ssh  tcp  --  anywhere             anywhere             multiport dports ssh

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Chain fail2ban-pam-generic (1 references)
target     prot opt source               destination
RETURN     all  --  anywhere             anywhere

Chain fail2ban-ssh (1 references)
target     prot opt source               destination
RETURN     all  --  anywhere             anywhere

Si l’on omet les références à fail2ban qui a inscrit des règles dans le pare-feu, nous avons trois instructions :

Chain INPUT (connexions entrantes)

Chain FORWARD (connexions transmises)

Chain OUTPUT (connexions sortantes)

avec pour politique de base : ACCEPT.

Pour le moment donc, notre pare-feu autorise tout le trafic internet.

 

Préparatifs

Avant de configurer notre pare-feu, nous allons déjà nous renseigner sur le fonctionnement de notre réseau et recueillir des informations importantes : l’adresse IP interne de notre réseau et celle du Pi.

Pour ce faire, sur le Raspberry Pi :

lambda_user@myweb:~ $ sudo ip route show
default via 192.168.0.254 dev eth0  metric 202 
192.168.0.0/24 dev eth0  proto kernel  scope link  src 192.168.0.15  metric 202

Nous notons que notre réseau interne est disponible sur l’interface eth0 aux adresses comprises entre 192.168.0.1 et 192.168.0.254, l’adresse du Pi étant 192.168.0.15.

Il est très important pour la suite de retenir la plage d’adresses disponibles sur le réseau interne : 192.168.0.0/24 (adresse de réseau et masque de réseau).

 

Nous allons ensuite trouver les adresses IP des ordinateurs connectés sur notre réseau interne après avoir installé nmap :

lambda_user@myweb:~ $ sudo apt install nmap

lambda_user@myweb:~ $ sudo nmap -sP 192.168.0.0/24

Starting Nmap 6.47 ( http://nmap.org ) at 2016-12-07 21:53 CET
Nmap scan report for 192.168.0.11
Host is up (-0.10s latency).
MAC Address: 44:8A:5B:5A:C4:AA (Micro-Star INT'L CO.)
Nmap scan report for 192.168.0.254
Host is up (0.00082s latency).
MAC Address: 00:07:D2:A8:C4:72 (Freebox SA)
Nmap scan report for 192.168.0.15
Host is up.
Nmap done: 256 IP addresses (3 hosts up) scanned in 5.92 seconds

L’utilitaire de scan nmap nous informe qu’il y a trois appareils branchés sur le réseau :

192.168.0.11 : l’ordinateur principal

192.168.0.254 : la box internet

192.168.0.15 : le raspberry pi.

Nous allons donc retenir l’IP de l’ordinateur principal depuis lequel nous commandons le Pi à savoir : 192.168.0.11.

 

Configuration d’iptables

Nous sommes maintenant prêt pour configurer iptables.

Cette configuration peut se faire de deux manières :

  • soit ligne à ligne avec la commande iptables -A …
  • soit en éditant un fichier que nous intégrons ensuite d’un bloc à iptables.

Il faut également savoir qu’iptables gère les deux protocoles internet existant : IPv4 et IPv6. Plutôt que d’écrire deux fichiers distincts, nous allons tout rassembler en un seul fichier.

 lambda_user@myweb:~ $ nano regles-iptables

 

Dans l’éditeur de texte qui s’ouvre nous allons copier le texte suivant, en prenant garde aux données surlignées en rouge :

 

* filter

# On remet toutes les règles à 0
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]

## REGLES DE TRAFIC ENTRANT

# Loopback entrant (autorisation du bouclage local)
-A INPUT -i lo -p all -j ACCEPT

# Rejet des connexions extérieures se faisant passer pour un bouclage local
-4 -A INPUT -s 127.0.0.0/8 ! -i lo -j DROP
-6 -A INPUT -s ::1/128 ! -i lo -j DROP

# Autorisation des connexions déjà établies
-A INPUT -m conntrack --ctstate ESTABLISHED -j ACCEPT

### Rejet des usurpations d'adresses (spoofing) : adresses externes se faisant passer pour une adresse interne

### ATTENTION !!! : COMMENTER (mettre un # devant) LA LIGNE CONCERNANT VOTRE RESEAU INTERNE (ici 192.168.0.0/24)###

-4 -A INPUT -s 10.0.0.0/8 -j DROP 
-4 -A INPUT -s 169.254.0.0/16 -j DROP
-4 -A INPUT -s 172.16.0.0/12 -j DROP
-4 -A INPUT -s 192.0.2.0/24 -j DROP
# -4 -A INPUT -s 192.168.0.0/24 -j DROP
-4 -A INPUT -s 224.0.0.0/4      -j DROP
-4 -A INPUT -d 224.0.0.0/4      -j DROP
-4 -A INPUT -s 240.0.0.0/5 -j DROP
-4 -A INPUT -d 240.0.0.0/5 -j DROP
-4 -A INPUT -s 0.0.0.0/8 -j DROP
-4 -A INPUT -d 0.0.0.0/8 -j DROP
-4 -A INPUT -d 239.255.255.0/24 -j DROP
-4 -A INPUT -d 255.255.255.255  -j DROP


#Protection contre les attaques par réflexion (smurf) : inondation de pings pour bloquer la machine
-4 -A INPUT -p icmp -m icmp --icmp-type address-mask-request -j DROP
-4 -A INPUT -p icmp -m icmp --icmp-type timestamp-request -j DROP
-4 -A INPUT -p icmp -m limit --limit 2/second --limit-burst 2 -j ACCEPT

# Protection contre Paquet Xmas (paquet de données très lourd pouvant saturer un serveur)
-A INPUT -p tcp --tcp-flags ALL FIN,PSH,URG -j DROP

# Protection contre les paquets invalides
-A INPUT -m state --state INVALID -j DROP
-A FORWARD -m state --state INVALID -j DROP
-A OUTPUT -m state --state INVALID -j DROP
-A INPUT -p tcp -m tcp --tcp-flags SYN,FIN SYN,FIN -j DROP
-A INPUT -p tcp -m tcp --tcp-flags SYN,RST SYN,RST -j DROP

# Protection attaque TCP reset (attaque pour fermer la connexion)
-A INPUT -p tcp -m tcp --tcp-flags RST RST -m limit --limit 2/second --limit-burst 2 -j ACCEPT

# Autorisation de certains types de connexions entrantes

#Autorisation complète du port 80 - HTTP - nécessaire à nextcloud
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT

#Autorisation complète du port 443 - HTTPS - nécessaire à nextcloud
-A INPUT -p tcp -m tcp --dport 443 -j ACCEPT

#Autorisation du port 22 - SSH uniquement pour le réseau local 

### ATTENTION !!! UTILISER LA PLAGE D'ADRESSES TROUVÉE PLUS HAUT AVEC sudo ip route show !!!
-4 -A INPUT -p tcp --dport 22 -s 192.168.0.0/24 -j ACCEPT


# Autoriser le ping
-4 -A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT
-6 -A INPUT -p icmpv6 -j ACCEPT


### REJETER TOUT LE RESTE DU TRAFIC ENTRANT
-A INPUT -j DROP


# REGLES DE TRAFIC SORTANT

## Loopback sortant
-A OUTPUT -o lo -j ACCEPT

## autoriser les connexions établies
-A OUTPUT -m conntrack --ctstate ESTABLISHED -j ACCEPT

# Autorisation des ports suivants vers l'extérieurs
# SMTP = 25 (protocole de mails sortants)
# DNS =53  (protocole de résolution de noms)
# HTTP = 80 (HTTP)
# ntp = 123 (protocole de synchronisation de l'heure)
# HTTPS = 443 (HTTPS)
# SSH = 22 (SSH) on ne remet pas de règles sortantes pour le ssh car nous avons autorisé les connexions établies
### 

-A OUTPUT -p tcp -m tcp --dport 25 -j ACCEPT
-A OUTPUT -p udp -m udp --dport 53 -j ACCEPT
-A OUTPUT -p udp -m udp --dport 123 -j ACCEPT
-A OUTPUT -p tcp -m tcp --dport 80 -j ACCEPT
-A OUTPUT -p tcp -m tcp --dport 443 -j ACCEPT

# Autorisation du ping
-4 -A OUTPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT
-6 -A OUTPUT -p icmpv6 -j ACCEPT

# REJET DU RESTE DU TRAFIC SORTANT
-A OUTPUT -j DROP

# REJET DU TRAFIC FORWARD
-A FORWARD -j DROP

COMMIT

 

Une fois recopié le texte dans l’éditeur nano :

Ctrl-o pour enregistrer,

Ctrl-x pour quitter.

 

Si on souhaite limiter l’accès SSH uniquement à un seul ordinateur de notre réseau interne, on remplace la ligne :

-4 -A INPUT -p tcp --dport 22 -s 192.168.0.0/24 -j ACCEPT

par la ligne :

-4 -A INPUT -p tcp --dport 22 -s 192.168.0.11 -j ACCEPT

en prenant bien garde d’utiliser les adresses trouvées préalablement avec les commandes ip route show et nmap.

 

Si au contraire on préfère autoriser l’accès SSH depuis n’importe quel réseau, on transforme la règle en :

-4 -A INPUT -p tcp --dport 22 -j ACCEPT

 

Maintenant que nos règles sont prêtes, nous allons les intégrer à iptables avec les deux commandes suivantes :

lambda_user@myweb:~ $ sudo iptables-restore < regles-iptables
lambda_user@myweb:~ $ sudo ip6tables-restore < regles-iptables

 

Nous vérifions que cela fonctionne :

lambda_user@myweb:~ $ sudo iptables -L

Chain INPUT (policy ACCEPT)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere            
DROP       all  --  loopback/8           anywhere            
ACCEPT     all  --  anywhere             anywhere             ctstate ESTABLISHED
(...)
ACCEPT     icmp --  anywhere             anywhere             icmp echo-request
DROP       all  --  anywhere             anywhere   
lambda_user@myweb:~ $

 

Nous vérifions tout de suite que nous n’avons pas fait d’erreur de configuration du SSH qui nous interdirait ensuite d’accéder au Raspberry Pi  en nous déconnectant puis reconnectant au SSH :

lambda_user@myweb:~ $ logout
Connection to 192.168.0.15 closed.

linux_user@linux $ ssh lambda_user@192.168.0.15
lambda_user@192.168.0.15's password: 

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Wed Dec  7 22:51:32 2016 from 192.168.0.11

lambda_user@myweb:~ $

 

Si par malheur nous n’arrivons pas à nous reconnecter, il suffit de débrancher le Pi et de le rebrancher. Les modifications que nous avons faites ne survivent pas (encore) à un reboot.

Il est également utile avant d’aller plus loin de nous connecter à Nextcloud depuis un navigateur pour vérifier que nous y avons toujours accès.

 

Enregistrer définitivement iptables

Une fois que nous sommes satisfaits de notre pare-feu, nous allons installer l’utilitaire iptables-persistent qui va enregistrer la configuration d’iptables et la restaurer à chaque reboot.

lambda_user@myweb:~ $ sudo apt install iptables-persistent
(...)
Setting up iptables-persistent (1.0.3+deb8u1) ...
lambda_user@myweb:~ $

La configuration d’iptables est maintenant enregistré dans deux fichiers : /etc/iptables/rules.v4 et /etc/iptables/rules.v6

Désormais pour modifier les règles d’iptables, il faudra modifier ces fichiers.

 

Le serveur Nextcloud est maintenant mieux protégé grâce au pare-feu que nous avons installé.

 

Article modifié le 17/12/2016 suite aux recommandations de Azlux concernant iptables (retrait de l’état RELATED et remplacement de la syntaxe state par conntrack)

You may also like...

11 Responses

  1. Antoine dit :

    Merci pour ce tuto détaillé et très bien commenté !

  2. BrigZ dit :

    Bonjour,

    Merci beaucoup pour vos Tutos, qui sont très claire et bien expliqué, cela aide grandement certain d’entre nous, présentement j’essaye de suivre le tuto installer Nextcloud 12 sur Raspberry Stretch

    Mais voilà, je dois avouer que je ne suis pas trop bien à l’aise avec Linux et Iptables (manque d’habitude), mais cela m’intéresse beaucoup.

    Hardware : Installation toute fraiche de Raspbian Stretch sur Raspberry Pi II, SDHC 8G

    Je souhaitais affiné la range IP “192.168.0.0/24” en la modifiant comme ceci “192.168.1.0/24”
    mais je crois que j’ai dû faire quelque chose de travers,
    car en exécutant la commande “sudo iptables -L” il y a 3 status invalide,
    ces règles sont déjà persistante
    (sudo iptables-restore < regles-iptables et sudo ip6tables-restore < regles-iptables)

    Voici la liste des erreurs

    Chain INPUT (policy ACCEPT)

    DROP all — anywhere anywhere state INVALID

    Chain FORWARD (policy ACCEPT)

    DROP all — anywhere anywhere state INVALID

    Chain OUTPUT (policy ACCEPT)

    DROP all — anywhere anywhere state INVALID

    Je ne sais pas trop ce que je dois modifier pour rectifier le tir ?

    Je ne souhaite pas utiliser l'IPv6, et pour l'instant j'ai commenter quelque lignes dans "/etc/hosts"
    # ::1 localhost ip6-localhost ip6-loopback
    # ff02::1 ip6-allnodes
    # ff02::2 ip6-allrouters

    Je devrai encore chercher pour désactiver complètement et proprement le protocole Pv6 …

    – En commençant votre tuto sur Iptables,
    au sujet de la commande "sudo ip route show" (sous stretch)
    j'ai été surpris de ne pas retrouver l'interface habituel "eth0",
    mais à la place s'affichait une suite de chiffres et de lettres du genre " enX112233445566".
    nouveau nom en rapport avec l'adresse MAC de l'interface Ethernet je présume

    Après quelques recherches, j'ai trouvé une petite astuce, si l'on veut retrouver son interface habituelle eth0, …, marche aussi avec wlan0, …

    voir ici : https://www.raspberrypi.org/forums/viewtopic.php?t=191030#p1199731

    Il faut éditer le fichier "cmdline.txt" avec la commande suivante : "sudo nano /boot/cmdline.txt"
    et y insérer "net.ifnames=0 " ici je l'ai placé en tout début de ligne,
    ensuite ctrl+o, ctrl+x, ensuite un petit reboot…

    Un petit test "sudo ip route show"

    default via 192.168.1.xxx dev eth0 src 192.168.1.xxx metric 202
    192.168.1.0/24 dev eth0 proto kernel scope link src 192.168.1.xxx metric 202

    Maintenant "eth0" est bien indiquer, et à partir de ce moment là j'ai pu commencer le tuto Iptables, voir la suite…

    Cordialement

    • SoozX dit :

      Bonjour Brigz,

      D’abord merci pour la remarque sur le changement de méthode dans l’assignation par défaut des noms de connexion de Debian (et donc de Raspbian) et sur la façon de revenir à l’ancienne. Je n’avais pas encore fait attention à cela.

      Concernant les lignes avec state INVALID que vous retrouvez dans la liste des règles Iptables, ce ne sont pas des erreurs mais bien une instruction que nous avons donnée pour se protéger des paquets invalides (ce sont les paquets qui sont invalides et non pas la règle iptables) :

      # Protection contre les paquets invalides
      -A INPUT -m state –state INVALID -j DROP
      -A FORWARD -m state –state INVALID -j DROP
      -A OUTPUT -m state –state INVALID -j DROP

      Si malgré tout vous devez changer les règles d’iptables une fois que iptables-persistent a été installé, il y a deux méthodes :
      – aller modifier /etc/iptables/rules.v4 et rules.v6 à la main
      – désinstaller et purger iptables-persistent (sudo apt purge iptables-persistent) et recommencer du début.
      Pour info, une table iptables vierge s’écrit de la façon suivante :

      * filter

      :INPUT ACCEPT [0:0]
      :FORWARD ACCEPT [0:0]
      :OUTPUT ACCEPT [0:0]

      COMMIT

      Pour l’IPV6, pour le désactiver complètement :
      # sudo nano /etc/sysctl.conf

      Rajouter à la fin
      net.ipv6.conf.all.disable_ipv6 = 1

      Enregistrer puis :
      # sudo sysctl -p

      Et normalement, en faisant :
      $ ip -6 a

      Vous ne devriez plus rien avoir, ce qui signifie que l’ipv6 a été désactivé.

      Pour le réactiver il faut modifier :
      net.ipv6.conf.all.disable_ipv6 = 1
      en
      net.ipv6.conf.all.disable_ipv6 = 0

      et rebooter.

  3. BrigZ dit :

    Merci soozX pour votre intervention rapide en rapport à Iptables
    et pour la désactivation de l’IPv6

    J’ai bien suivis la procédure pour désactiver l’IPv6
    et effectivement la commande “ip -6 a” ne renvois plus rien, c’est parfait.

    Cependant je vais recommencer toute la procédure à partir d’une clean install de Raspbian toujours en version Stretch, car jusqu’ici tout c’est bien passé 😉 et c’est temps mieux

    mais… un peu plus loin, cela n’a pas été aussi bien en suivant toujours le tuto pour installer Nextcloud sur Raspberry …
    je pense faire une image de la carte SD étape par étape avec image writer (sous windows)
    et tenter de poursuivre ce très intéressant tuto,
    et en cas d’échec… je restaurerai facilement le travail déjà effectué.

  4. Dioz dit :

    Bonjour SoozX,

    Bravo pour ce tutoriel qui explique très bien comment sécuriser le raspbian.
    J’ai néanmoins un soucis avec le fichier de configuration que vous proposez.
    Il m’est impossible de faire du FTP client.
    J’ai beau ajouté les lignes suivantes :
    -A INPUT -p tcp –sport 21 -m state –state ESTABLISHED -j ACCEPT
    -A INPUT -p tcp –sport 20 -m state –state ESTABLISHED,RELATED -j ACCEPT
    -A INPUT -p tcp –sport 1024: –dport 1024: -m state –state ESTABLISHED -j ACCEPT

    -A OUTPUT -p tcp –dport 21 -m state –state NEW,ESTABLISHED -j ACCEPT
    -A OUTPUT -p tcp –dport 20 -m state –state ESTABLISHED -j ACCEPT
    -A OUTPUT -p tcp –sport 1024: –dport 1024: -m state –state ESTABLISHED,RELATED,NEW -j ACCEPT

    Rien n’y fait, je peux me connecter à mon serveur FTP distant mais impossible de faire quelconque manipulation comme ls / put / get.

    Auriez-vous une “correction” à me proposer ?
    Merci

    • SoozX dit :

      Bonjour,
      Pour que je comprenne bien, le raspberry Pi est-il client ou serveur FTP ?

      • Dioz dit :

        Il est simplement client.

        • SoozX dit :

          Je ne suis pas spécialiste d’IPtables, mais il manque peut-être le module conntrack pour que cela marche.

          Pour vérifier, sur le Pi :
          $ lsmod | grep ftp

          Si la commande ne retourne rien, le module conntrack n’est pas chargé.

          Si il est chargé, il devrait y avoir 2 lignes ressemblant à ça :
          nf_conntrack_ftp 7045 0
          nf_conntrack 104800 4 nf_conntrack_ipv6,nf_conntrack_ftp,nf_conntrack_ipv4,xt_conntrack

          Pour le charger, taper la commande :
          $ sudo modprobe nf_conntrack_ftp
          et vérifier ensuite avec
          $ lsmod | grep ftp

          Si ça ne résout pas le problème, pour le décharger :
          $ sudo modprobe -r nf_conntrack_ftp

          Si par contre c’est bien la solution, il faut ajouter à /etc/modules une ligne à la fin :
          $ sudo nano /etc/modules
          ip_conntrack_ftp

          Cela évitera d’avoir à refaire le modprobe à chaque reboot.

  5. Dioz dit :

    Oui j’ai vu en effet que le module nf_conntrack_ftp pouvait être nécessaire.
    J’ai donc ajouté l’insertion du module au démarrage du serveur mais aucun changement de comportement.
    Je ne vais pas polluer le fil de discussion avec mon cas perso.
    Merci en tout cas pour les retours et la rapidité.

  6. olinox14 dit :

    Formidable! Extraordinaire! 10 jours que je me galère, avec mes connaissances trés basiques de debian, à installer ce serveur nextcloud sur mon pi3, et surtout à le sécuriser. 10 jours à suivre des explications, des docs et des tutos vagues et incomplets qui me menaient de problème en problèmes parce qu’il me manquait une étape et là… paf: le Graal! Merci beaucoup!

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *