IT & Engineering
Guide de sécurité : comment protéger votre infrastructure des attaques les plus courantes
Gérer votre infrastructure dans une configuration sécurisée est une tâche ardue, même pour les professionnels de la sécurité. Ce guide fournit des conseils pratiques pour aider l’équipe d’ingénierie à concevoir une infrastructure respectant les bonnes pratiques de sécurité, afin qu’elle puisse déployer ses services sur l’Internet public en toute confiance et réduire le risque de compromission. Ce guide cible spécifiquement les systèmes basés sur Linux ; cependant, les bonnes pratiques s’appliquent à tous les systèmes informatiques.
Gérer votre infrastructure dans une configuration sécurisée est une tâche ardue, même pour les professionnels de la sécurité. Ce guide fournit des conseils pratiques pour aider l’équipe d’ingénierie à concevoir une infrastructure respectant les bonnes pratiques de sécurité, afin qu’elle puisse déployer ses services sur l’Internet public en toute confiance et réduire le risque de compromission. Ce guide cible spécifiquement les systèmes basés sur Linux ; cependant, les bonnes pratiques s’appliquent à tous les systèmes informatiques.
Gérer une infrastructure en toute confiance implique de comprendre contre quoi et contre qui vous la protégez. Ce guide comportera à terme trois versions, Base, Intermédiaire et Avancée, chacune étant axée sur la défense de votre infrastructure contre un type d’attaquant différent.
Vous lisez la version de Base, qui vise à vous protéger contre les attaques automatisées et les apprentis pirates qui comprennent les outils d’exploitation plutôt que les techniques d’exploitation. Ce type d’attaquant est opportuniste plutôt que ciblé, et passe rapidement à des cibles plus faciles. Si vous gérez un projet parallèle ou créez une entreprise, c’est le meilleur point de départ pour vous aider à bâtir des fondations solides.
En lisant ce guide, réfléchissez au type d’attaquant et aux types d’attaques contre lesquels vous souhaitez vous défendre. Les bonnes pratiques que vous appliquez ou non dépendent de ce que vous essayez de défendre et contre qui vous essayez de vous défendre.
Check-list de sécurité réseau
Ce guide suit ces principes directeurs dans son approche de la sécurité des logiciels :
- Défendre, détecter et réagir. Cela signifie appliquer de bonnes pratiques de sécurité pour défendre votre infrastructure, mais aussi journaliser tout comportement suspect et, en cas de compromission, restaurer l’état de sécurité.
- Tout logiciel peut être exploité. Tout logiciel non trivial comporte des failles qui permettent à un attaquant suffisamment motivé de les exploiter.
- La simplicité, c’est la sécurité. Les systèmes trop complexes deviennent plus difficiles à appréhender pour l’équipe de développement et plus faciles à exploiter pour un attaquant. Les systèmes plus simples et compréhensibles sont souvent plus sécurisés. Ne déployez pas une solution de sécurité que vous ne comprenez pas.
- L’obscurité n’est pas la sécurité. Fiez-vous à la sécurité des protocoles que vous utilisez pour défendre votre infrastructure, et non à des ports obscurs et autres astuces pour tenter de dissimuler des protocoles non sécurisés.
- Considérez toutes les saisies utilisateur comme hostiles. Considérez toutes les saisies acceptées de la part des utilisateurs comme hostiles, et vérifiez rigoureusement ce que vous acceptez.
- Principe du moindre privilège. Fournissez les privilèges minimums nécessaires à l’exécution d’une opération. Si un processus ou un système est exploité, vous ne voulez pas permettre à un attaquant d’obtenir plus d’accès que le strict minimum.
Vulnérabilités logicielles
Appliquer de manière agressive des mises à jour de sécurité pour des logiciels que vous n’avez pas écrits peut sembler une mauvaise façon de protéger votre infrastructure, voire inutile. Cependant, c’est l’un des meilleurs investissements en temps que vous puissiez faire d’un point de vue de la sécurité. Voici deux exemples de problèmes de sécurité récents que des attaquants inexpérimentés utilisant des outils automatisés peuvent exploiter si vous n’avez pas mis à jour vos serveurs avec les derniers correctifs de sécurité :
- Heartbleed : permet à un attaquant de voler vos certificats privés et de déchiffrer le trafic chiffré
- Shellshock : permet à un attaquant d’exécuter à distance du code arbitraire sur vos serveurs
Ces deux problèmes suffiraient à donner à un attaquant le contrôle total de toute votre infrastructure. Heureusement, atténuer ces bugs n’est pas difficile.
Comment réduire les dommages liés aux vulnérabilités logicielles
Appliquez systématiquement les mises à jour de sécurité fournies par le fournisseur de votre système d’exploitation. La plupart des fournisseurs proposent une méthode automatisée. Par exemple, pour les systèmes basés sur Debian, vous pouvez utiliser Unattended Upgrades,et pour les systèmes basés sur Red Hat, vous pouvez utiliser AutoUpdates.
L’application automatisée de correctifs est excellente, cependant, elle présente un inconvénient potentiel (pour votre entreprise) si vous ne testez pas vos logiciels avant d’appliquer les correctifs sur les serveurs de production : des pannes inattendues peuvent survenir. Bien que les responsables des paquets essaient de s’assurer que les mises à jour de sécurité ne contiennent pas de modifications majeures, ils ne peuvent pas tester toutes les combinaisons possibles avant le déploiement. C’est pourquoi il est important de disposer d’un système de test d’intégration continue/déploiement continu (CI/CD) ou de tester manuellement les mises à jour de sécurité avant de les déployer sur les serveurs de production.
Cependant, il ne suffit pas d’appliquer ces mises à jour de sécurité. Si le problème se trouve dans une bibliothèque partagée, vous continuerez d’utiliser son ancienne version et resterez vulnérable aux attaques jusqu’à ce que vous redémarriez le processus qui y est lié. Pour vérifier si des binaires doivent être redémarrés, vous pouvez utiliser checkrestart pour les systèmes basés sur Debian et needs-restarting pour les systèmes basés sur Red Hat.
Résumé
- À FAIRE : mettez vos serveurs à jour pour les protéger contre les dernières vulnérabilités de sécurité.
- À FAIRE : utilisez les mises à jour automatiques du fournisseur de votre système d’exploitation chaque fois que possible.
- À FAIRE : redémarrez les services qui s’appuient sur des bibliothèques partagées ayant été mises à jour.
- À NE PAS FAIRE : ne déployez pas de mises à jour sur un serveur sans effectuer de tests au préalable.
Durcissement du réseau
Qu’est-ce que le durcissement du réseau ?
Le durcissement de votre application à l’aide des outils du système d’exploitation est une approche efficace pour limiter l’étendue des dommages que les attaquants peuvent causer après avoir exploité une vulnérabilité dans votre application. Cette section se concentre sur l’utilisation des outils traditionnels de contrôle d’accès Unix, que la plupart des utilisateurs connaissent, afin de restreindre votre application à l’ensemble minimal d’accès dont elle a besoin pour fonctionner. Ces outils sont les autorisations sur les fichiers, l’identifiant utilisateur (UID) et l’accès root.
L’objectif de cette section n’est pas de durcir votre application au point qu’un attaquant ne puisse pas la compromettre. C’est un objectif presque impossible. Le but est de limiter ce qu’un attaquant peut faire une fois que votre application a été compromise. Après avoir exploité votre application, un attaquant pourra effectuer des actions en tant que cette application, et potentiellement élever ses privilèges au niveau root, ce qui lui donne un accès total et complet à votre système d’exploitation. Le but est plutôt de restreindre les actions que votre application peut effectuer au strict nécessaire pour fonctionner, ce qui restreint par conséquent l’attaquant.
Comment réduire les dommages grâce au durcissement du réseau
Vous devez restreindre votre application de manière à ce que, même si un attaquant a exploité votre processus et peut exécuter du code en tant que ce compte utilisateur, ce dernier ait des droits d’accès limités sur le système de fichiers. Le même concept s’applique au processus sous lequel le compte est exécuté : restreignez le temps de processeur, la mémoire et le nombre de descripteurs de fichier pour atténuer les attaques de type DoS où l’attaquant épuise vos ressources. Le but est d’obliger l’attaquant à utiliser une attaque par élévation de privilèges (exploiter une autre partie de votre système d’exploitation pour élever ses privilèges au-delà de l’application en cours d’exécution) pour effectuer une action significative sur votre système.
Pour restreindre le compte sous lequel votre application s’exécute, suivez les directives suivantes :
- N’exécutez jamais votre application en tant que root ou utilisateur ayant des capacités sudo. Si votre application est exploitée, cela signifie en pratique que l’attaquant peut obtenir les privilèges root.
- Si vous avez plusieurs applications et que chacune accède à des données sensibles différentes, envisagez d’exécuter chacune sous son propre compte, puis d’utiliser les privilèges du système de fichiers pour isoler l’accès aux données sensibles des unes et des autres. Cela signifie que les données sensibles de l’application ne doivent jamais avoir d’autres autorisations configurées pour permettre des autorisations de lecture et d’écriture à quiconque. Par exemple, ne définissez jamais les autorisations sur une valeur telle que
0777; utilisez plutôt une valeur telle que0660. - Assurez-vous que l’utilisateur et le groupe de l’application disposent de privilèges limités. Cela implique de créer un nouvel utilisateur et un nouveau groupe limités pour le compte, sans donner de shell à l’utilisateur. Supposons que vous ayez une application nommée
foo. Créez un utilisateur nomméfooappet définissez son répertoire de base sur/var/appdata/fooapp:sudo useradd -r -s /bin/false --home /var/appdata/fooapp fooapp sudo mkdir /var/appdata/fooapp sudo chown fooapp:fooapp /var/appdata/fooapp - Transformez votre application en démon pour qu’elle démarre automatiquement sous un utilisateur particulier. Il existe deux approches générales pour résoudre ce problème. La première consiste à utiliser les outils du système d’exploitation (comme les scripts d’initialisation System V (Red Hat / Debian) ou systemd (Red Hat/ Debian) pour démarrer et arrêter votre application, puis utiliser un outil de surveillance des processus (comme monit) pour redémarrer votre application si elle plante. L’autre approche consiste à utiliser un système de contrôle des processus (comme supervisord, skarnet s6, daemontools) qui lancera votre application en tant que processus enfant et la redémarrera également si elle plante. Ces deux approches sont tout à fait valables, et le choix dépend de celle qui s’intègre le mieux à votre flux de travail.
Pour restreindre le processus exécutant votre application, suivez les directives suivantes :
- Attribuez des limites par processus à l’aide du fichier
/etc/security/limits.conf. Par exemple, si vous souhaitez limiter le nombre de descripteurs de fichiers ouverts à dix et la mémoire à 1 Go, ajoutez les lignes suivantes au fichier/etc/security/limits.conf:
fooapp hard nofile 10 # limite de dix descripteurs de fichiers ouverts fooapp hard as 1000000 # limite de 1 Go
- Ne liez pas votre application à un port inférieur. En général, vous devez exécuter votre application avec des privilèges d’administrateur pour ce faire. Liez-la plutôt à un numéro de port supérieur et utilisez un proxy inverse pour transférer vos requêtes vers votre application. Utilisez ensuite les capacités de Linux pour permettre à votre proxy inverse de se lier à un port inférieur sans aucun autre privilège. Par exemple, si vous avez un proxy inverse dans
/opt/rproxy, vous pouvez définir ses capacités comme suit :
setcap 'cap_net_bind_service=+ep' /opt/rproxy
- Enfin, envisagez d’utiliser
chroot, mais gardez à l’esprit que cela implique une surcharge de maintenance.chrootvous permet de limiter la portée de ce qu’un processus peut voir sur le système de fichiers ; plus précisément, il modifie votre répertoire racine pour le définir sur le répertoire de votre choix. Par exemple, si vous définissez/var/chrootcomme nouveau répertoire racine, les processus verront les fichiers sous/var/chrootcomme étant sous/. Bien que ce soit plus sécurisé, cela signifie que toutes les bibliothèques partagées que votre processus pourrait utiliser doivent être copiées et résider dans/var/chroot. Par conséquent, chaque fois que vous appliquez des mises à jour de sécurité, vous devez également recopier les bibliothèques partagées mises à jour. Vous pouvez éviter cette maintenance avec des liens physiques, mais vous offrez alors un chemin vers l’extérieur qu’un attaquant pourrait exploiter. D’autres approches (basées sur les cgroups) offrant des avantages similaires seront abordées dans la version intermédiaire de ce guide.
Résumé
- À FAIRE : créez un compte restreint pour exécuter votre application, ce qui implique de ne pas avoir de shell et de limiter l’accès au système de fichiers.
- À FAIRE : liez votre application à un port supérieur, ce qui vous permet de l’exécuter en tant qu’utilisateur non privilégié.
- À FAIRE : utilisez les capacités au lieu de root chaque fois que possible.
- À NE PAS FAIRE : n’utilisez pas chroot, à moins d’être prêt à assumer la surcharge de maintenance.
Sécurité du pare-feu réseau
Comment examiner les règles du pare-feu
Des règles de pare-feu strictes vous permettent de définir quelles communications entrantes et sortantes sont autorisées depuis vos serveurs. Commencer par une politique de refus par défaut et n’autoriser que du trafic spécifique entrant et sortant vous oblige à réfléchir à l’ensemble minimal de services que vous souhaitez exposer, ce qui peut réduire votre risque d’attaque. Un processus errant ne peut pas exposer toute votre infrastructure au grand public, à moins que vous ne l’ayez expressément autorisé.
Cette section se concentre sur les règles de pare-feu entrant et les paramètres de la pile TCP/IP. Bien que les règles de pare-feu sortant soient très efficaces pour limiter jusqu’où un attaquant peut aller après s’être introduit dans votre infrastructure, la prochaine version de ce guide se concentrera sur celles-ci.
Atténuation
Premières règles de pare-feu. Lorsque vous créez un script pour les règles de pare-feu, utilisez les principes directeurs suivants :
- Supprimez les règles de pare-feu existantes. Lors de l’élaboration de règles de pare-feu, vous devez avoir une idée cohérente de ce que vous bloquez et autorisez. Supprimer toutes les règles existantes et repartir de zéro permet d’y parvenir.
- Définissez la règle par défaut pour le trafic entrant sur DROP. Cela respecte le principe du moindre privilège. Après avoir défini la politique par défaut sur DROP, vous pouvez ouvrir progressivement votre réseau, élément par élément.
- Autorisez le libre accès à l’interface de bouclage. Contrairement aux interfaces externes, lier votre processus à localhost est généralement bon pour la sécurité. Par conséquent, restreindre l’accès à l’interface de bouclage cause plus de tort que de bien. Cela vous expose effectivement à une attaque d’un utilisateur local, mais c’est un risque que vous devez évaluer par vous-même.
- Ne coupez aucune connexion établie. Vous voulez éviter de couper votre propre connexion SSH à un serveur, et vous assurer que toute requête en cours puisse aboutir avant d’être interrompue.
- Ne restreignez pas tout le trafic Internet Control Message Protocol (ICMP). Autoriser l’ICMP est essentiel au fonctionnement d’Internet ; les routeurs et les hôtes l’utilisent pour communiquer des informations critiques comme la disponibilité des services, la taille des paquets et la présence des hôtes. Les types 3 et 4 (Destination Unreachable et Source Quench) sont critiques, et les restreindre causera plus de problèmes que d’avantages à l’avenir. Si vous craignez de permettre à un attaquant de cartographier votre réseau, un compromis raisonnable consiste d’abord à limiter le débit de tout le trafic ICMP, puis à n’autoriser qu’un sous-ensemble limité de ce trafic sur vos hôtes de périphérie, tout en permettant un accès sans entrave pour la communication interne entre hôtes.
- Appliquez des contrôles de sécurité de base. Certains trafics entrants n’ont aucune utilité légitime ; restreignez-les. Si vous êtes fréquemment la cible d’attaques par un type de trafic particulier, il peut être utile d’en faire une chaîne dédiée si vous devez souvent ajouter des règles à cette section.
- À moins que vous n’utilisiez réellement l’IPv6 et ne prévoyiez de créer des règles de pare-feu pour le trafic IPv6, restreignez tout trafic IPv6 entrant.
Voici un script commenté qui remplit tous ces objectifs :
Voici un petit script pour le trafic IPv6 :
Ces règles sont désormais exécutées en mémoire, et vous devez vous assurer qu’elles seront chargées au prochain redémarrage de votre système d’exploitation. Pour les systèmes basés sur Debian, cela signifie soit ajouter vos règles de pare-feu à /etc/network/ip-pre-up.d/ soit ajouter une commande pre-up à /etc/network/interfaces. Pour les systèmes Red Hat, cela se fait généralement en utilisant la commande /sbin/service iptables save.
De plus, il est recommandé de durcir et d’optimiser la pile TCP/IP comme suit :
- Si vous utilisez des règles de pare-feu à état, comme dans l’exemple précédent, veillez à augmenter le nombre maximum de connexions que vous pouvez suivre. Dans le cas contraire, un attaquant peut utiliser une attaque par déni de service distribué (DDoS) contre vous.
- Utilisez les cookies SYN pour prévenir les attaques DoS par inondation SYN. Thomas Pornin explique très bien ce que sont les attaques par inondation SYN et comment les cookies SYN permettent d’atténuer ce type d’attaque.
- Journalisez tous les paquets martiens car tout paquet provenant d’une adresse source ou de destination non routable est très probablement malveillant.
Vous pouvez tester tous les paramètres ci-dessus avec le script suivant :
Pour que ces paramètres soient conservés après un redémarrage, mettez à jour /etc/sysctl.conf :
Résumé
- À FAIRE : refusez le trafic par défaut. N’autorisez explicitement que le trafic dont vous savez qu’il doit traverser votre réseau.
- À NE PAS FAIRE : ne restreignez pas unilatéralement l’ICMP.
- À FAIRE : autorisez le libre accès à l’interface de bouclage.
- À FAIRE : imposez des contrôles de sécurité de base.
- À FAIRE : assurez-vous que vos règles sont chargées au redémarrage.
- À FAIRE : optimisez votre pile TCP/IP pour augmenter le nombre de connexions suivies et protéger contre les inondations SYN.
Connexion à distance
Description
En matière de connexion à distance, vous devez vous assurer non seulement que les communications avec vos serveurs sont chiffrées, mais aussi que seuls les utilisateurs autorisés y ont accès. Voici les objectifs typiques de la sécurisation des connexions à distance :
- Accordez un accès limité aux utilisateurs afin que la compromission d’un compte ne compromette pas toute votre infrastructure.
- Une cryptographie forte garantit qu’un indiscret ne puisse pas lire vos communications.
- Les attaquants ne doivent pas pouvoir utiliser des techniques de force brute pour se connecter à vos serveurs.
- Même si votre clé est compromise, un attaquant ne doit pas pouvoir accéder à votre infrastructure.
- Un attaquant qui utilise des techniques de force brute ne doit pas pouvoir épuiser les ressources du serveur.
- Seuls les utilisateurs autorisés doivent avoir accès à vos serveurs.
- Il ne doit exister aucune connexion pour les comptes d’administration à usage général. Toutes les actions d’administration doivent être effectuées via une forme d’élévation de privilèges (
sudo) afin de journaliser les actions réalisées.
Le non-respect de l’un de ces objectifs peut constituer un risque pour la sécurité. Une cryptographie faible (ou inexistante) peut permettre à un attaquant de consulter vos communications. Une authentification faible peut permettre à des utilisateurs non autorisés d’accéder à vos systèmes.
Heureusement, Secure Shell (SSH) atténue la plupart de ces risques, et avec quelques ajustements mineurs sur vos systèmes, tous peuvent être évités.
Atténuation
Pour commencer, générez correctement votre clé SSH en vous assurant d’utiliser une taille de clé suffisamment grande, et en protégeant votre clé par une phrase secrète. Vous pouvez le faire en utilisant ssh-keygen :
ssh-keygen -t rsa -b 4096 -C foo@example.com
Ensuite, à l’invite, saisissez une phrase secrète ! Une phrase secrète garantit que même si quelqu’un vole votre clé, il ne pourra pas l’utiliser sans la connaître.
OpenSSH dispose d’une configuration par défaut raisonnable et plutôt sécurisée. Cependant, certaines distributions peuvent affaiblir ces paramètres par défaut pour assurer l’interopérabilité d’OpenSSH avec des serveurs plus anciens. La configuration suivante permet simplement de s’assurer que ces paramètres par défaut raisonnables sont appliqués par votre version d’OpenSSH. Pour plus d’informations détaillées sur la configuration d’OpenSSH, consultez le Guide de configuration de Mozilla pour OpenSSH et la page Securing SSH pour CentOS. Ce sont deux excellentes ressources, et nous nous appuierons sur ces configurations dans les prochaines versions de ce guide.
Sur le serveur, assurez-vous que les lignes suivantes figurent dans le fichier /etc/ssh/sshd_config :
Cette configuration permet d’atteindre les objectifs suivants :
- Le Protocole 2 garantit que vous utilisez une version sécurisée du protocole SSH. La version 1 du protocole présente plusieurs problèmes et est considérée comme obsolète .
PasswordAuthentication noetPubkeyAuthentication yesvous obligent à utiliser la cryptographie à clé publique, et non des mots de passe, pour vous authentifier sur vos serveurs. Bien que vous puissiez avoir un mot de passe fort, s’il s’agit d’un mot de passe de 2 048 bits généré aléatoirement et encodé en ASCII, la plupart des mots de passe sont mauvais et les longueurs de mot de passe couramment utilisées offrent un espace de recherche bien plus réduit qu’une grande clé.PermitRootLogin nodésactive la possibilité de se connecter à distance en tant qu’utilisateur root. Bien que ce ne soit pas un problème directement exploitable, la désactivation de cette connexion à distance vous aide à conserver de bons journaux d’audit pour comprendre ce qui se passe sur vos serveurs. Le compte root agit comme un compte d’administration partagé, ce qui limite votre capacité à vérifier quel utilisateur effectue quelle action privilégiée. Si vous obligez tous les utilisateurs à passer par leur propre compte, vous disposerez d’une trace vérifiable de qui a effectué quelle action. Des détails sur la configuration de la journalisation d’audit sont fournis dans une section ultérieure.LogLevel VERBOSEjournalise l’utilisateur et l’empreinte de la clé qui ont tenté de s’authentifier. Là encore, ce paramètre n’atténue pas directement un exploit, mais est utile pour les audits.
Sur le client, assurez-vous que les lignes suivantes figurent dans le fichier /etc/ssh/ssh_config :
Cette configuration permet d’atteindre les objectifs suivants :
- Le Protocole 2 garantit que vous utilisez une version sécurisée du protocole SSH. La version 1 du protocole présente plusieurs problèmes et est considérée comme obsolète .
HashKnownHosts yeshache les noms d’hôtes et les adresses dans votre fichier~/.ssh/known_hosts. Même si un attaquant vole votre fichier known hosts, il ne peut pas simplement énumérer les hôtes auxquels vous vous connectez avec votre clé.StrictHostKeyChecking askvérifie la clé qui vous est présentée par rapport à celle de votre fichier~/.ssh/known_hostset, si elle a changé (ou si c’est la première fois que vous visitez cet hôte), vous demande si vous l’acceptez. Cela permet d’atténuer les attaques de l’homme du milieu.
Enfin, accordez aux utilisateurs un accès limité à votre infrastructure. Par exemple, tous les utilisateurs n’ont pas besoin d’accéder à vos serveurs de sauvegarde ; ne donnez accès qu’à ceux qui savent réellement comment restaurer à partir des sauvegardes. Cela garantit que même si le compte d’un utilisateur non habilité pour les sauvegardes est compromis, l’intégrité de vos sauvegardes n’est pas remise en cause.
Pour y parvenir, deux des approches les plus courantes sont :
- Les comptes utilisateurs locaux. Dans cette approche, vous créez des comptes Unix locaux pour vos utilisateurs et ne les créez que sur les serveurs auxquels ils doivent accéder. Vous pouvez utiliser les commandes
newusersetuserdelpour ce faire, et automatiser/orchestrer cela à l’aide d’outils de gestion de configuration comme Chef ou Ansible. - Un service d’authentification centralisé comme LDAP. Avec cette approche, les serveurs auxquels chaque utilisateur a accès sont définis et stockés dans la configuration du serveur LDAP.
Résumé
- À FAIRE : protégez votre clé avec une phrase secrète.
- À NE PAS FAIRE : ne supposez pas que votre distribution a des paramètres par défaut acceptables ; définissez rigoureusement ce qui est important pour votre infrastructure.
- À FAIRE : utilisez la cryptographie à clé publique pour l’authentification plutôt que l’authentification par mot de passe.
- À NE PAS FAIRE : n’accordez pas un accès libre à tous les utilisateurs ; limitez l’accès aux parties de votre infrastructure qui sont nécessaires.
Limites de confiance
Description
Les limites de confiance sont un endroit courant où se produisent les vulnérabilités de sécurité. La limite entre le monde extérieur et votre infrastructure interne est sacrée, et vous devez faire tout votre possible pour la défendre et vous assurer que seuls les utilisateurs autorisés peuvent la franchir.
Vous devriez vous préoccuper de deux limites de confiance principales. La première est la limite entre l’Internet public et le point de terminaison de votre API ; c’est celle que votre clientèle franchira chaque jour en utilisant votre service. La seconde est un point d’accès pour votre équipe de développement et d’administration système, qui servira à déployer et entretenir votre application.
Pour la limite de confiance de l’API que votre clientèle traversera, vous devez considérer chaque saisie utilisateur comme hostile, et présumer que chaque requête est en fait une tentative d’exploitation de votre infrastructure. En considérant les requêtes des utilisateurs sous cet angle, il devient évident que vous devez réduire au maximum la surface d’attaque que vous leur offrez, et isoler les dommages pouvant survenir lorsqu’un utilisateur finit par exploiter votre service.
Pour la limite de confiance que vous franchissez pour assurer le service de vos applications, vous devez isoler tous vos services afin qu’ils ne soient pas exposés à l’Internet public, puis obliger les utilisateurs qui y accèdent depuis Internet à traverser un point d’accès bien gardé que vous pouvez défendre (appelons cela un hôte bastion). Vous pouvez concentrer toutes vos ressources sur ce point d’accès unique et vous soucier moins de la façon dont vos services communiquent entre eux lorsqu’ils se trouvent dans cette limite de confiance.
Atténuation
Pour atténuer ces problèmes de limite de confiance, vous devez imaginer les boîtes distinctes dans lesquelles vous pouvez placer l’Internet public et votre infrastructure (voir le schéma suivant). Une fois cela fait, vous pouvez commencer à réfléchir à la manière de défendre votre infrastructure.
La première grande boîte est l’Internet public. Vous ne devriez jamais faire confiance à qui que ce soit ou à quoi que ce soit sur l’Internet public. En fait, vous devriez considérer tous les acteurs sur l’Internet public comme hostiles, même lorsqu’il s’agit de vos propres employés se connectant en SSH à vos serveurs.
La deuxième grande boîte est votre infrastructure interne. Ce sont vos hôtes de confiance. Les services exécutés sur ces serveurs ne doivent écouter que sur des interfaces réseau privées dans la mesure du possible, et ne pas être directement exposés à l’Internet public.
Les deux boîtes qui chevauchent les deux sont votre hôte de rebond et vos hôtes d’API. Ces hôtes doivent avoir accès à la fois à l’Internet public et à votre infrastructure interne. Étant donné qu’ils sont directement exposés à l’Internet public, ils doivent être durcis et exécuter l’ensemble minimal de services requis pour effectuer leurs tâches.
Renforcement du point de terminaison de l’API
Bien que nous ne puissions pas nous attendre à ce qu’un service soit exempt de bugs, nous pouvons limiter dans quelle mesure un attaquant peut exploiter votre infrastructure s’il parvient à exploiter votre service. C’est pourquoi nous recommandons d’isoler les services qui acceptent les requêtes entrantes et de les exécuter sur leurs propres serveurs dédiés.
Vous pouvez y parvenir en divisant les requêtes entrantes en deux parties : l’équilibrage de charge et la terminaison TLS (Transport Layer Security) des requêtes entrantes, ainsi que le traitement de la requête par votre service lui-même. Ces deux éléments devraient au minimum constituer des processus distincts, voire s’exécuter sur des serveurs différents, avec l’équilibrage de charge et la terminaison TLS sur la limite non approuvée/approuvée. Cette section se concentrera sur l’équilibrage de charge et la terminaison (le durcissement de l’application a été abordé dans une section précédente).
En séparant l’équilibrage de charge et la terminaison TLS de votre application, vous limitez la possibilité qu’un bug dans votre équilibreur de charge ou votre logiciel TLS ne dégénère en une exploitation de l’ensemble de votre application, qui contiendra généralement des informations sensibles chargées en mémoire. Cela vous donne également un point de maintenance (et de défaillance) unique à corriger lorsqu’une vulnérabilité est détectée et que vous devez mettre à niveau votre bibliothèque TLS, une tâche de plus en plus courante.
Par exemple, supposons qu’un attaquant exploite un bug d’exécution de code à distance (RCE) comme GHOST ou un bug de lecture arbitraire de la mémoire (comme Heartbleed) dans votre serveur HTTP ou votre logiciel TLS. Si votre serveur HTTP, la terminaison TLS et la logique de l’application se trouvent tous dans le même processus, un bug dans l’un d’eux donne à l’attaquant accès à des informations sensibles dans les autres composants. Par exemple, un bug dans OpenSSL peut donner à un attaquant accès aux clés sensibles que votre application a chargées en mémoire. À l’inverse, un bug dans votre application peut potentiellement donner à un attaquant accès à vos certificats SSL. Cependant, si vous séparez ces éléments, l’exploitation de l’un n’affecte pas l’autre, et vous ne perdez que quelques données sensibles.
Pour l’équilibrage de charge, les choix courants sont NGINX, HAProxy, et Apache. La terminaison TLS s’effectue généralement avec OpenSSL ; cependant, des alternatives comme LibreSSL et Mozilla NSS existent. Une autre alternative consiste à utiliser une solution comme vulcand, qui agit comme un équilibreur de charge et utilise la bibliothèque Go TLS pour la terminaison TLS.
Renforcement du point de terminaison du service (et de tout le reste)
Vous pouvez renforcer votre point de terminaison de service en restreignant l’accès à vos serveurs depuis l’Internet public et en obligeant toutes les authentifications à passer par un hôte de rebond. Cette restriction est généralement obtenue en n’exposant pas directement votre infrastructure à l’Internet public, et en créant à la place une sorte de réseau interne accessible uniquement via l’hôte bastion.
Il existe de nombreuses façons de créer un réseau interne, et votre approche dépendra en grande partie de la façon dont votre infrastructure est configurée par votre fournisseur de services et de vos préférences.
Par exemple, supposons que vous hébergiez vos serveurs sur Amazon Web Services (AWS). Vous pouvez alors commencer par un Virtual Private Cloud (VPC) avec un seul sous-réseau public. Vos serveurs seront isolés des autres serveurs sur AWS et résideront dans leur propre bloc CIDR 10.0.0.0/16. Cependant, ils auront toujours un accès libre à Internet. Pour restreindre l’accès depuis Internet, créez des groupes de sécurité qui isolent à la fois les ports ouverts et les serveurs pouvant y accéder. Par exemple, vous configureriez vos hôtes de travail pour accepter les connexions sur les ports 22 et 80, mais uniquement depuis votre hôte de rebond et votre équilibreur de charge, respectivement. Votre serveur de rebond, en revanche, accepterait les connexions sur le port 22 depuis n’importe quel serveur sur l’Internet public.
Si votre fournisseur de services ne propose pas ces outils, vous pouvez accomplir les mêmes choses à condition qu’il prenne en charge un type de réseau privé, partagé ou dédié, qui vous permette d’isoler le trafic public et privé. Cette fonctionnalité est généralement proposée par la plupart des fournisseurs : comme mentionné précédemment, Amazon l’appelle VPC, Rackspace l’appelle ServiceNet, et Digital Ocean l’appelle Private Networking. Tous offrent fondamentalement la même capacité : lorsque vous créez votre serveur virtuel, vous pouvez le lier à l’interface publique, à l’interface privée ou aux deux. Si votre fournisseur de services ne dispose pas de cette capacité au moment de la création, vous pouvez activer et désactiver ces interfaces vous-même dans le fichier /etc/network/interfaces sur un système basé sur Debian, et dans le fichier /etc/sysconfig/network-scripts/ifcfg* sur un système basé sur Red Hat.
Une fois que vous avez des serveurs disposant d’interfaces publiques et privées, utilisez iptables pour restreindre le trafic entrant sur les interfaces accessibles publiquement aux serveurs agissant comme hôtes de rebond ou exécutant l’API accessible publiquement. Les serveurs gérant tous les services internes, comme votre application et votre serveur de base de données, n’autorisent aucun trafic entrant vers les interfaces publiques, et restreignent le trafic entrant sur les interfaces privées à l’ensemble des serveurs de confiance.
Une fois que vous avez accompli cela, la seule façon pour un attaquant d’exploiter votre infrastructure depuis l’Internet public est de passer par votre hôte bastion durci ou d’exploiter votre API d’une manière ou d’une autre.
Enfin, pour accéder à ces serveurs, n’utilisez pas ssh-agent ; utilisez plutôt ProxyCommand. Bien que ssh-agent ait son utilité, ce n’est pas une bonne solution pour ce cas d’utilisation spécifique. Si vous l’utilisiez, quiconque disposant d’un exploit d’élévation de privilèges local pour votre serveur bastion pourrait accéder à n’importe quel serveur de votre infrastructure en se faisant passer pour toute personne dont les clés sont actuellement chargées en mémoire par ssh-agent. À l’inverse, avec ProxyCommand, vos clés ne seront pas laissées en mémoire à la portée d’un vol, et votre clé privée résidera exclusivement sur votre poste de travail local ; seule votre clé publique sera copiée sur chaque serveur auquel vous devez accéder.
Pour utiliser ProxyCommand, copiez votre clé publique dans ~/.ssh/authorized_hosts sur tous les serveurs auxquels vous devez accéder. Ensuite, sur votre poste de travail, mettez à jour votre fichier ~/.ssh/config avec les informations suivantes :
Cette configuration vous permet d’accéder à server1.example.com et server2.example.com depuis workstation.example.com via SSH sur leurs interfaces privées en « rebondissant » par jump.example.com, qui a accès aux interfaces publiques et privées. Il vous suffit de taper ssh server1.example.com ou ssh server2.example.com pour vous connecter.
Résumé
- À FAIRE : utilisez un équilibreur de charge pour séparer le serveur HTTP de votre application de votre serveur HTTP public.
- À FAIRE : terminez le TLS au niveau de l’équilibreur de charge.
- À FAIRE : utilisez un hôte de rebond durci pour contrôler l’accès à votre infrastructure.
- À NE PAS FAIRE : n’utilisez pas l’agent SSH, si possible. Cela risque d’exposer toutes vos clés si quelqu’un dispose d’un exploit d’élévation de privilèges local.
- À FAIRE : utilisez les interfaces publiques et privées fournies par votre fournisseur de services pour isoler vos services internes de l’Internet public.
Surveillance et journalisation
Description
Toute mesure de sécurité peut être et sera contournée à un moment donné. Puisqu’aucune mesure de sécurité pratique ne peut offrir de garanties infaillibles, il est important de disposer de solides outils de surveillance et de journalisation pour vous aider à comprendre où et comment vos systèmes ont été compromis. Mieux vous comprendrez comment fonctionnent vos systèmes et ce qui s’y exécute, mieux vous serez en mesure de détecter un comportement anormal. De la même manière qu’une banque installe des caméras de sécurité tout en sécurisant ses coffres, disposer de bons outils de surveillance est essentiel pour attraper ces hackers astucieux qui ont déjoué vos mesures de sécurité.
La surveillance et la journalisation prennent deux formes. La première est la surveillance en direct, qui vous permet de voir ce qui se passe sur votre système à tout moment. Cela englobe tout, des sockets réseau ouverts aux processus en cours d’exécution. La seconde correspond aux données de journalisation des actions qui ont déjà été effectuées. Cela couvre tout, de la journalisation de la logique d’application aux journaux système.
Dans cette section, nous aborderons la consultation des journaux système sur les serveurs individuels eux-mêmes. Dans la version intermédiaire de ce guide, nous parlerons de l’agrégation des journaux et des alertes.
Atténuation
Les outils suivants sont inclus dans la plupart des systèmes d’exploitation basés sur Unix. Ils sont utiles lorsque vous soupçonnez qu’un incident de sécurité est en cours, mais il est également essentiel de les utiliser en amont afin de comprendre leur sortie normale.
Surveillance en direct
Voici quelques commandes et leurs résultats attendus dans des conditions de fonctionnement normales. Ces exemples illustrent ce à quoi la sortie devrait ressembler sur votre système
who – Indique qui est connecté en ce moment.
last -a – Affiche une liste des derniers utilisateurs connectés. Affiche le nom d’utilisateur, l’heure de connexion, ainsi que les adresses IP utilisées pour la connexion.
netstat -plntu – Affiche les noms des processus et les ports sur lesquels ils écoutent les connexions.
netstat -ap – Affiche un flux en direct de toutes les connexions, y compris les connexions sortantes établies.
find / -mtime -1 -ls | head -n 20 – Répertorie les 20 premiers fichiers modifiés au cours des 24 dernières heures.
faillog -a pour voir un résumé des échecs de connexion. Cela est également utile pour limiter le nombre maximal d’échecs de connexion pour un utilisateur.
tcpdump -i eth1 -s 0 -A tcp port http – Capture tout le trafic HTTP sur l’interface eth1. Cela est utile si vous avez trouvé quelque chose de suspect en utilisant netstat et que vous souhaitez approfondir. Ce guide ne peut pas vous donner tous les tenants et aboutissants de tcpdump, mais il existe une variété de ressources sur Internet pour vous aider à comprendre tcpdump.
Surveillance des journaux
Voici quelques règles générales sur la gestion de la journalisation des applications et des indications sur les journaux système importants.
Journaux généraux des applications
Regroupez les journaux de votre application dans un emplacement central, qu’il s’agisse d’un fichier journal ou d’un répertoire unique. L’approche courante consiste à utiliser syslog pour cela. L’utilisation de syslog facilitera l’envoi des journaux vers un serveur de journalisation central à l’avenir.
Conservez vos journaux aussi longtemps que l’espace disque le permet. Conserver les journaux jusqu’à 90 jours sur le disque n’est pas déraisonnable si vous en avez la place.
Journaux système
Tout comme pour la surveillance en direct, il est recommandé de consulter régulièrement les fichiers journaux système suivants afin de définir une bonne base de référence de la sortie attendue. Disposer d’une base de référence permet de repérer beaucoup plus facilement les comportements suspects par la suite. Voici une liste partielle des journaux système intéressants à surveiller :
/var/log/auth.log– Journaux d’authentification du système./var/log/syslog– Si vous n’envoyez pas les journaux à une installation syslog particulière, ils se trouveront ici./var/log/messages– Messages généraux du journal système.~/.bash_history– Liste des commandes Bash qui ont été exécutées par l’utilisateur. Ce journal peut être facilement manipulé ou effacé par des attaquants expérimentés./var/log/utmpet/var/log/wtmp– Ces journaux contiennent les utilisateurs actuellement connectés et l’historique de tous les utilisateurs connectés. Utilisezlast -fpour afficher ces fichiers.
Résumé
- Apprenez quelques commandes de base qui peuvent vous aider à comprendre ce qui se passe actuellement sur vos serveurs. Ces commandes incluent
who,last,lsof,netstat,faillogetfind. - Déterminez ce que vous devez journaliser. Les journaux ne sont d’aucune utilité s’ils ne capturent pas les événements critiques pour la sécurité. Au minimum, surveillez les fichiers suivants :
/var/log/auth.log,/var/log/sysloget/var/log/messages. - Commencez à centraliser vos journaux le plus tôt possible. Utiliser syslog dès maintenant plutôt qu’un framework de journalisation personnalisé facilitera l’envoi des journaux vers un serveur de journalisation central à l’avenir.
Utilisation de la cryptographie
Description
La cryptographie est un sujet complexe qui devrait être traité à part entière. Même les oublis ou les erreurs les plus infimes peuvent entraîner la compromission totale de la sécurité d’un produit. C’est pourquoi le mantra « ne créez pas votre propre cryptographie » est si souvent répété. Deux bonnes sources à lire avant de commencer avec la cryptographie sont Crypto101 écrit par Laurens Van Houtven (lvh) et les défis cryptographiques matasano.
Cela étant dit, la sécurisation de votre infrastructure nécessite une certaine utilisation de la cryptographie, et il existe des modèles courants pouvant être utilisés en toute sécurité. Cette section couvre l’un de ces modèles : comment stocker des données sensibles dans le code source (ou sur le disque).
Atténuation
Lorsque vous stockez des identifiants, que ce soit dans le contrôle de code source ou sur disque, ne les stockez pas en clair (non chiffrés). Vous pourriez penser que vos mots de passe sont en sécurité si vous utilisez un dépôt privé GitHub, mais il ne faut pas s’en remettre uniquement à GitHub pour protéger toute votre infrastructure des attaquants. Si vous chiffrez vos identifiants, vous pouvez préserver votre sécurité même si GitHub est compromis.
Lorsque vous recherchez un outil ou une bibliothèque pour chiffrer de petites quantités de données, tenez compte des recommandations suivantes :
- Utilisez un algorithme de chiffrement symétrique moderne. Deux candidats couramment suggérés sont AES et Salsa20 (NaCl).
- Si votre chiffrement symétrique prend en charge différents modes, choisissez-le avec soin. Par exemple, CBC est un bon mode à utiliser avec AES, mais pas ECB.
- Utilisez un code d’authentification de message (MAC) pour vous assurer que les données chiffrées n’ont pas été altérées. HMAC-SHA-512 ou Poly1305 sont de bons candidats.
- Utilisez une source d’entropie de haute qualité, ce qui signifie généralement utiliser
/dev/urandompour obtenir les nombres aléatoires employés dans les clés, les sels et les nonces. - Si la bibliothèque ou l’outil fonctionne avec des phrases secrètes, assurez-vous qu’il utilise une KDF pour transformer la phrase secrète en clé.
Vous pouvez créer vous-même un outil de chiffrement, cependant comme mentionné, cela peut être délicat et n’est pas recommandé. Cependant, si vous tenez absolument à le faire, utilisez une bibliothèque comme NaCl ou cryptography.io qui se chargera au moins de la cryptographie pour vous. Cependant, il est encore préférable d’utiliser une « recette » conçue à cet effet par quelqu’un d’autre, telle que lemma ou Fernet qui exposent toutes deux une API simple que vous pouvez utiliser pour chiffrer et déchiffrer des données en toute sécurité.
Résumé
- À NE PAS FAIRE : ne choisissez pas au hasard le mode de votre algorithme de chiffrement symétrique.
- À FAIRE : utilisez un algorithme de chiffrement symétrique authentifié avec un MAC.
- À FAIRE : utilisez
/dev/urandompour générer des éléments aléatoires. - À FAIRE : utilisez une « recette » telle que ou si vous le pouvez.
Sauvegardes
Description
Bien que les sauvegardes puissent ne pas sembler appartenir à la même catégorie que les autres sujets abordés dans ce guide, elles sont tout aussi importantes pour la sécurité de l’infrastructure. Les sauvegardes ont deux objectifs principaux : restaurer en cas de défaillance matérielle non malveillante, et restaurer en cas de compromission de votre infrastructure par un attaquant. N’oubliez pas, en cas de compromission, il est préférable d’effacer votre serveur et d’en créer un nouveau plutôt que d’essayer de supprimer les logiciels malveillants, ce qui peut s’avérer difficile, voire impossible, pour un novice. C’est pourquoi les sauvegardes sont essentielles en cas de compromission pour remettre votre infrastructure en état de fonctionnement sécurisé.
Atténuation
Les approches suivantes constituent une bonne stratégie générale à suivre lorsque vous travaillez avec des sauvegardes :
- Ne négligez pas la sécurité de vos sauvegardes sous prétexte qu’elles ne semblent pas critiques pour votre service. Les attaquants ciblent fréquemment l’infrastructure de sauvegarde précisément pour cette raison.
- Sauvegardez aussi souvent que nécessaire en fonction des besoins de votre entreprise. Une fois par jour est raisonnable.
- Vos serveurs de sauvegarde doivent avoir un accès limité, et les comptes existants doivent utiliser des mécanismes d’authentification et d’autorisation différents de ceux utilisés pour le reste de votre infrastructure. Par exemple, vos serveurs de sauvegarde doivent utiliser une clé SSH différente pour la connexion. Si vous suivez ces recommandations et que votre environnement principal est compromis, vous disposerez toujours de sauvegardes de confiance à partir desquelles vous pourrez restaurer.
- Si vous ne souhaitez pas gérer votre propre infrastructure de sauvegarde, sauvegardez vers un entrepôt de données tiers comme Amazon S3. Notez que si vous comptez utiliser un service tiers, vous devez chiffrer vos sauvegardes avant de leur envoyer vos données. Travaillez en partant du principe que votre entrepôt de données est public, et utilisez le chiffrement pour protéger vos données. En adoptant cette approche, même si votre hôte est compromis, vos données sont en sécurité.
- Si vous utilisez Amazon S3 ou Rackspace CloudFiles, utilisez une recette de chiffrement authentifié telle que lemma ou Fernet. Si vous ne voulez pas vous soucier de la cryptographie, utilisez un service qui chiffre vos données côté client et n’envoie que des blobs chiffrés à son service, comme Tarsnap.
- Sauvegardez vos dépôts de code source, tous les logiciels tiers que votre application utilise et votre base de données. L’exemple récent de FoundationDB illustre l’importance de sauvegarder tout logiciel que vous utilisez. Les téléchargements de logiciels peuvent être révoqués par l’équipe de développement à tout moment et pour n’importe quelle raison.
- Bien que les systèmes de contrôle de version distribués (DVCS) comme Git offrent une certaine redondance, ils ne remplacent pas les véritables sauvegardes. Il ne faut pas dépendre de la présence d’une branche particulière sur le poste de travail d’un collègue pour assurer la continuité de l’activité.
- Sauvegardez votre base de données en utilisant la méthode prescrite par celle-ci.
- Restaurez à partir des sauvegardes aussi souvent que vous les exécutez. Les sauvegardes ne sont d’aucune utilité si elles ne sont pas utilisables. Idéalement, vous devriez pouvoir exécuter sur vos sauvegardes restaurées certains services auxiliaires qui ne nécessitent pas les données les plus récentes. Ainsi, si quelque chose se passe mal, vous le saurez immédiatement.
- Assurez-vous que plusieurs membres de votre équipe sont capables de restaurer à partir des sauvegardes. Vous pourrez peut-être trouver comment restaurer vos sauvegardes, ou peut-être pas. Cela peut prendre une heure ou dix heures. Il est préférable de consacrer quelques heures par trimestre à examiner votre infrastructure de sauvegarde avec un ou une collègue.
Résumé
- À NE PAS FAIRE : n’utilisez pas les mêmes comptes pour les sauvegardes que pour votre environnement principal.
- À FAIRE : sauvegardez les dépôts sources, les logiciels tiers et les bases de données.
- À FAIRE : tentez de restaurer à partir de sauvegardes aussi souvent que vous exécutez la procédure de sauvegarde.
- À FAIRE : exécutez des services auxiliaires à partir des sauvegardes restaurées si vous le pouvez.
- À NE PAS FAIRE : ne créez pas de point de défaillance unique ; assurez-vous que plusieurs membres de votre équipe sont capables d’effectuer la restauration.
- À FAIRE : chiffrez vos sauvegardes avec un algorithme de chiffrement authentifié. Utilisez un outil comme lemma ou Fernet, ou une solution hébergée comme Tarsnap.
Comment se protéger contre les vulnérabilités logicielles