Comment sécuriser PostgreSQL contre les attaques automatisées

introduction

Il peut être tentant de penser qu’un serveur vient d’être installé, voit peu de trafic ou n’offre rien qui puisse sembler intéressant aux hackers et qui ne passera pas inaperçu. Cependant, de nombreux exploits sont automatisés et spécialement conçus pour rechercher les erreurs de configuration courantes. Ces programmes analysent les réseaux pour découvrir les serveurs, indépendamment de la nature du contenu.

L'autorisation de connexions à distance est l'une des situations courantes et plus facilement rectifiées pouvant conduire à l'exploitation d'une base de données PostgreSQL. Cela est dû au fait que certaines configurations facilitent la découverte du serveur par de tels programmes.

Dans ce didacticiel, nous montrerons comment atténuer le risque spécifique lié à l’autorisation de connexions à distance. Bien qu'il s'agisse d'une première étape importante, étant donné que les serveurs peuvent être compromis par d'autres moyens, nous vous recommandons également de prendre des mesures supplémentaires pour protéger vos données, décrites dans lesAdditional Security Considerations.

Contexte

Pour comprendre le risque spécifique que nous atténuons, imaginez le serveur en tant que magasin. Si le serveur écoute sur n’importe quel port, c’est un peu comme si vous allumiez un panneau «Ouvrir» au néon. Il rend le serveur lui-même visible sur le réseau, où les scripts automatisés peuvent le trouver.

Nous pouvons considérer chaque port comme un moyen d'entrer dans le magasin, comme une porte ou une fenêtre. Ces entrées peuvent être ouvertes, fermées, verrouillées ou cassées selon l’état du logiciel en cours d’écoute, mais écouter sur une interface publique signifie qu’un script cherchant à pénétrer à l’intérieur peut commencer à essayer. Par exemple, le script peut être configuré pour tenter de vous connecter avec un mot de passe par défaut s’il n’a pas été modifié. Il pourrait tenter des exploits connus du démon d’écoute au cas où il n’aurait pas été corrigé. Peu importe ce que le script essaie, s'il est capable de trouver une faiblesse et de l'exploiter, l'intrus est à l'intérieur et peut s'attaquer sérieusement à la tâche de compromettre le serveur.

Lorsque nous limitons un démon commepostgresql à l’écoute locale, c’est comme si cette porte particulière n’existait pas. Il n’ya pas d’étape suivante à essayer, du moins en ce qui concerne Postgres. Les pare-feu et les VPN protègent de la même manière. Dans ce didacticiel, nous allons nous concentrer sur la suppression de PostgreSQL en tant que porte accessible au public. Pour sécuriser le démon lui-même ou les données telles qu'elles sont transmises ou stockées, voirAdditional Security Considerations.

Conditions préalables

Dans ce didacticiel, nous utiliseronstwo Ubuntu installations, un pour l'hôte de la base de données et un autre comme client qui se connectera à l'hôte à distance. Chacun doit avoir un utilisateursudo et le pare-feu activé. Le guide,Initial Server Setup with Ubuntu 16.04 peut vous aider.

One Ubuntu 16.04 PostgreSQL Database Host:

Si vous n’avez pas encore installé PostgreSQL, vous pouvez le faire avec les commandes suivantes:

sudo apt-get update
sudo apt-get install postgresql postgresql-contrib

One Ubuntu 16.04 Client Machine:
Afin de démontrer et tester l’autorisation des connexions à distance, nous utiliserons le client PostgreSQL,psql. Pour l'installer, utilisez les commandes suivantes:

sudo apt-get update
sudo apt-get install postgresql-client

Lorsque ces conditions préalables sont en place, vous êtes prêt à les suivre.

Comprendre la configuration par défaut

Lorsque PostgreSQL est installé à partir des packages Ubuntu, il est par défaut limité à l'écoute sur localhost. Cette valeur par défaut peut être modifiée en remplaçant leslisten_addresses dans le fichierpostgresql.conf, mais la valeur par défaut empêche le serveur d'écouter automatiquement sur une interface publique.

De plus, le fichierpg_hba.conf n'autorise que les connexions depuis les sockets de domaine Unix / Linux et l'adresse de bouclage locale pour le serveur, il n'accepterait donc pas les connexions d'hôtes externes:

remplacer

# Put your actual configuration here
# ----------------------------------
#
# If you want to allow non-local connections, you need to add more
# "host" records.  In that case you will also need to make PostgreSQL
# listen on a non-local interface via the listen_addresses
# configuration parameter, or via the -i or -h command line switches.

# DO NOT DISABLE!
# If you change this first entry you will need to make sure that the
# database superuser can access the database using some other method.
# Noninteractive access to all databases is required during automatic
# maintenance (custom daily cronjobs, replication, and similar tasks).
#
# Database administrative login by Unix domain socket
local   all             postgres                                peer

# TYPE  DATABASE        USER            ADDRESS                 METHOD

# "local" is for Unix domain socket connections only
local   all             all                                     peer
# IPv4 local connections:
host    all             all             127.0.0.1/32            md5
# IPv6 local connections:
host    all             all             ::1/128                 md5

Ces valeurs par défaut répondent à l'objectif de ne pas écouter sur une interface publique. Si nous les laissons intactes et maintenons notre pare-feu en marche, nous avons terminé! On peut passer directement auxAdditional Security Considerations pour savoir comment sécuriser les données en transit.

Si vous devez vous connecter à partir d’un hôte distant, nous expliquerons comment remplacer les valeurs par défaut ainsi que les mesures immédiates que vous pouvez prendre pour protéger le serveur dans la section suivante.

Configuration des connexions à distance

Pour une configuration de production et avant de commencer à travailler avec des données sensibles, idéalement, le trafic PostgreSQL ™ sera crypté avec SSL en transit, sécurisé derrière un pare-feu externe ou protégé par un réseau privé virtuel (VPN). À mesure que nous travaillons dans cette direction, nous pouvons passer à l’étape un peu moins compliquée d’activer un pare-feu sur notre serveur de base de données et de limiter l’accès aux hôtes qui en ont besoin.

[[step-1 -—- add-a-user-and-database]] == Étape 1 - Ajout d'un utilisateur et d'une base de données

Nous allons commencer par ajouter un utilisateur et une base de données qui nous permettra de tester notre travail. Pour ce faire, nous utiliserons le client PostgreSQL,psql, pour nous connecter en tant qu'utilisateur administratifpostgres. En passant l'option-i àsudo, nous exécuterons le shell de connexion de l'utilisateur postgres, qui garantit que nous chargeons les options à partir des.profile ou d'autres ressources spécifiques à la connexion. -u espèces l'utilisateur postgres:

sudo -i -u postgres psql

Ensuite, nous allons créer un utilisateur avec un mot de passe. Veillez à utiliser un mot de passe sécurisé à la place de l'exemple ci-dessous:

CREATE USER sammy WITH PASSWORD 'password';

Lorsque l'utilisateur est créé avec succès, nous devrions recevoir le résultat suivant:

OutputCREATE ROLE

[.note] #Note: Depuis PostgreSQL 8.1, ROLES et USERS sont synonymes. Par convention, un rôle qui a un mot de passe est toujours appelé USER, tandis qu'un rôle qui ne l'est pas est appelé ROLE, donc parfois nous verrons ROLE en sortie où nous pourrions nous attendre à voir USER.
#

Ensuite, nous allons créer une base de données et accorder un accès complet à notre nouvel utilisateur. Les meilleures pratiques recommandent de n'accorder aux utilisateurs que l'accès dont ils ont besoin et uniquement sur les ressources où ils devraient en disposer. Par conséquent, selon le cas d'utilisation, il peut être judicieux de restreindre encore davantage l'accès d'un utilisateur. Vous pouvez en savoir plus sur les autorisations dans le guideHow To Use Roles and Manage Grant Permissions in PostgreSQL on a VPS.

CREATE DATABASE sammydb OWNER sammy;

Lorsque la base de données est créée avec succès, nous devrions recevoir la confirmation:

OutputCREATE DATABASE

Maintenant que nous avons créé un utilisateur et une base de données, nous allons quitter le moniteur

\q

Après avoir appuyé sur ENTREE, nous serons à l'invite de commande et prêts à continuer.

[[step-2 -—- configuring-ufw]] == Étape 2 - Configurer UFW

Dans le prérequisInitial Server Setup with Ubuntu 16.04, nous avons activé UFW et autorisé uniquement les connexions SSH. Avant de commencer notre configuration, vérifions le statut de UFW:

sudo ufw status

[.Remarque]##

Note: Si la sortie indique que le pare-feu estinactive, nous pouvons l'activer avec:

sudo ufw enable

Une fois activé, réexécutez la commande status,sudo ufw status affichera les règles actuelles. Si nécessaire, assurez-vous d'autoriser SSH.

sudo ufw allow OpenSSH

Sauf si nous avons apporté des modifications aux conditions préalables, le résultat devrait indiquer que seul OpenSSH est autorisé:

OutputStatus: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere
OpenSSH (v6)               ALLOW       Anywhere (v6)

Maintenant que nous avons vérifié l’état du pare-feu, nous allons autoriser l’accès au port PostgreSQL et le limiter à l’hôte ou aux hôtes à autoriser.

La commande ci-dessous ajoutera la règle pour le port par défaut de PostgreSQL, qui est 5432. Si vous avez modifié ce port, veillez à le mettre à jour à l'aide de la commande ci-dessous. Assurez-vous d’avoir utilisé l’adresse IP du serveur à accéder. Si nécessaire, relancez cette commande pour ajouter chaque adresse IP du client nécessitant un accès:

sudo ufw allow from client_ip_address to any port 5432

Pour revérifier la règle, nous pouvons exécuter à nouveauufw status:

sudo ufw status
OutputTo                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere
5432                       ALLOW       client_ip_address
OpenSSH (v6)               ALLOW       Anywhere (v6)

[.note] #Note: Si vous êtes nouveau dans UFW, vous pouvez en savoir plus dans le guideUFW Essentials: Common Firewall Rules and Commands.
#

Avec cette règle de pare-feu en place, nous allons maintenant configurer PostgreSQL pour qu’il écoute sur son adresse IP publique. Cela nécessite une combinaison de deux paramètres, une entrée pour l'hôte se connectant danspg_hba.conf et la configuration des listen_addresses danspostgresql.conf.

[[step-3 -—- configuration-the-allowed-hosts]] == Étape 3 - Configuration des hôtes autorisés

Nous allons commencer par ajouter l'entrée d'hôte danspg_hba.conf. Si vous avez une version différente de PostgreSQL installée, assurez-vous de la remplacer dans le chemin ci-dessous:

sudo nano /etc/postgresql/9.5/main/pg_hba.conf

Nous placerons les ligneshost sous le bloc de commentaires qui décrit comment autoriser les connexions non locales. Nous allons également inclure une ligne avec l’adresse publique du serveur de base de données afin que nous puissions rapidement vérifier que notre pare-feu est configuré correctement. Assurez-vous de remplacer le nom d'hôte ou l'adresse IP des machinesyour dans l'exemple ci-dessous.

Extrait de pg_hba.conf

# If you want to allow non-local connections, you need to add more
# "host" records.  In that case you will also need to make PostgreSQL
# listen on a non-local interface via the listen_addresses
# configuration parameter, or via the -i or -h command line switches.
host  sammydb  sammy   client_ip_address/32   md5

Avant de sauvegarder nos modifications, concentrons-nous sur chacune des valeurs de cette ligne si vous souhaitez modifier certaines des options:

  • host Le premier paramètre,host, établit qu'une connexion TCP / IP sera utilisée.

  • database `sammydb` La deuxième colonne indique à quelle (s) base (s) de données l'hôte peut se connecter. Plusieurs bases de données peuvent être ajoutées en séparant les noms par des virgules.

  • usersammy indique l'utilisateur autorisé à établir la connexion. Comme pour la colonne de base de données, plusieurs utilisateurs peuvent être spécifiés, séparés par des virgules.

  • address L'adresse spécifie l'adresse ou les adresses de l'ordinateur client et peut contenir un nom d'hôte, une plage d'adresses IP ou d'autresspecial key words. Dans l'exemple ci-dessus, nous n'autorisons que l'adresse IP unique de notre client.

  • auth-method Enfin, la méthode d'authentification,md5 indique qu'undouble-MD5-hashed password sera fourni pour l'authentification. Vous devrez simplement fournir le mot de passe créé pour l'utilisateur qui se connecte.

Pour une discussion plus complète de ces paramètres et d'autres paramètres, consultez la documentation PostgreSQL deThe pg_hba.conf File.

Une fois que vous avez terminé, enregistrez et quittez le fichier.

[[step-4 -—- configuration-de-l'adresse-d'écoute]] == Étape 4 - Configuration de l'adresse d'écoute

Ensuite, nous allons définir l'adresse d'écoute dans le fichierpostgresql.conf:

sudo nano /etc/postgresql/9.5/main/postgresql.conf

Trouvez la lignelisten_addresses et en dessous, définissez vos adresses d'écoute, en veillant à remplacer le nom d'hôte ou l'adresse IP de votre hôte de base de données. Vous voudrez peut-être vérifier que vous utilisez bien l’IP publique du serveur de base de données, et non le client qui se connecte:

postgresql.conf

#listen_addresses = 'localhost'         # what IP address(es) to listen on;
listen_addresses = 'localhost,server_ip_address'

Lorsque vous avez terminé, enregistrez et quittez le fichier.

[[step-5 -—- restarting-postgresql]] == Étape 5 - Redémarrage de PostgreSQL

Nos modifications de configuration ne prendront effet que lorsque nous aurons redémarré le démon PostgreSQL. Nous le ferons donc avant de tester:

sudo systemctl restart postgresql

Puisquesystemctl ne fournit aucun commentaire, nous vérifierons l'état pour nous assurer que le démon a redémarré avec succès:

sudo systemctl status postgresql

Si la sortie contient «Actif: actif» et se termine par quelque chose comme ce qui suit, le démon PostgreSQL est en cours d'exécution.

Output...
Jan 10 23:02:20 PostgreSQL systemd[1]: Started PostgreSQL RDBMS.

Maintenant que nous avons redémarré le démon, nous sommes prêts à tester.

[[step-6 -—- testing]] == Étape 6 - Test

Enfin, vérifions que nous pouvons nous connecter à partir de notre ordinateur client. Pour ce faire, nous utiliseronspsql avec-U pour spécifier l'utilisateur,-h pour spécifier l'adresse IP du client et-d pour spécifier la base de données, puisque nous ' Nous avons renforcé notre sécurité afin que lessammy ne puissent se connecter qu'à une seule base de données.

psql -U sammy -h postgres_host_ip -d sammydb

Si tout est configuré correctement, vous devriez recevoir l'invite suivante:

OutputPassword for user sammy:

Entrez le mot de passe que vous avez défini précédemment lorsque vous avez ajouté l'utilisateursammy dans le moniteur PostgreSQL.

Si vous arrivez à l’invite suivante, vous êtes connecté avec succès:

[secondary_label]
sammydb=>

Cela confirme que nous pouvons passer à travers le pare-feu et nous connecter à la base de données. Nous allons sortir maintenant:

\q

Puisque nous avons confirmé notre configuration, nous finirons par le nettoyage.

[[step-7 -—- remove-the-test-database-and-user]] == Étape 7 - Suppression de la base de données de test et de l'utilisateur

De retour sur l'hôte une fois que nous avons terminé de tester la connexion, nous pouvons utiliser les commandes suivantes pour supprimer la base de données et l'utilisateur.

sudo -i -u postgres psql

Pour supprimer la base de données:

DROP DATABASE sammydb;

L'action est confirmée par la sortie suivante:

OutputDROP DATABASE

Pour supprimer l'utilisateur:

DROP USER sammy;

Le succès est confirmé par:

OutputDROP ROLE

Nous terminerons notre nettoyage en supprimant l’entrée hôte de la base de donnéessammydb du fichierpg_hba.conf puisque nous n’en avons plus besoin:

sudo nano /etc/postgresql/9.5/main/pg_hba.conf

Ligne à supprimer depg_hba.conf

host  sammydb  sammy   client_ip_address/32   md5

Pour que la modification soit prise en compte, nous allons enregistrer et quitter, puis redémarrer le serveur de base de données:

sudo systemctl restart postgresl

Pour être sûr qu'il a bien redémarré, nous allons vérifier l'état:

sudo systemctl status postgres

Si nous voyons «Actif: actif», nous saurons que le redémarrage a réussi.

À ce stade, nous pouvons procéder à la configuration de l'application ou du service sur le client devant se connecter à distance.

Considérations de sécurité supplémentaires

Ce tutoriel est destiné à atténuer les risques posés par l’autorisation de connexions distantes non sécurisées à PostgreSQL, une situation courante qui expose par inadvertance PostgreSQL à des exploits. Limiter l’accès au port d’écoute à un ou plusieurs hôtes spécifiques ne règle pas d’autres problèmes de sécurité importants, tels que le cryptage de vos données en transit.

Avant de travailler avec des données réelles, nous vous recommandons de consulter les ressources suivantes et de prendre les mesures appropriées à votre cas d'utilisation.

  • Les instructionsSecurity within PostgreSQL: GRANT déterminent quels utilisateurs sont autorisés à accéder à une base de données particulière, tandis que les rôles établissent les privilèges de ces utilisateurs. Ensemble, ils permettent de séparer plusieurs bases de données au sein d’une même installation.

  • Setting up SSL with PostgreSQL: la configuration de SSL cryptera les données en transit. Cela protège les données au fur et à mesure de leur envoi.

  • Securing PostgreSQL TCP/IP Connections with SSH Tunnels: les tunnels SSH sont utiles lors de la connexion avec des clients qui ne sont pas compatibles SSL. Dans presque toute autre situation, il est préférable de configurer SSL avec Postgres.

Conclusion

Dans ce didacticiel, nous avons pris des mesures essentielles pour empêcher la publication de notre installation PostgreSQL en configurant le pare-feu du serveur pour autoriser les connexions uniquement à partir des hôtes nécessitant un accès et en configurant PostgreSQL pour accepter les connexions provenant uniquement de ces hôtes. Cela atténue le risque de certains types d’attaques. Il ne s’agit que de la première étape de la sécurisation des données. Nous vous recommandons d’examiner et de mettre en œuvre les mesures de sécurité supplémentaires décrites ci-dessus.