34 votes

comment sécuriser un port PostgreSQL ouvert

Donc, voici la situation. Il semble que nous devions avoir un port TCP 5432 ouvert sur le monde, où un client a accès à sa base de données PostgreSQL.

Pour des raisons évidentes, nous ne pouvons pas dire simplement "non", mais seulement en dernier recours.

Quels sont les principaux problèmes ? Comment puis-je défendre nos infrastructures ?

Quoi qu'il en soit, pourquoi ne devrait pas qu'il soit ouvert au monde ? Je pense que c'est peut-être plus sûr qu'un serveur FTP vieux de 20 ans et non entretenu.

P.S. Le VPN n'est pas bon. Certains cryptages peut-être (si je peux lui donner une URL de connexion JDBC qui travaux ).

4 votes

Les tunnels SSH ne sont pas une option ? Cet article pratique utilise en fait des tunnels PostgreSQL à titre d'exemple. Vous pourriez fournir au client un client SSH préconfiguré pour faciliter la connexion.

0 votes

La base de données sera utilisée par une application Java développée en interne sur une centaine de machines de l'entreprise. Notre seul moyen de les configurer est de donner une url de connexion jdbc à leur administration locale, tout autre moyen est très, très problématique.

0 votes

@milkman que fait l'application ? peut-être pourrait-elle interroger un serveur RESTful à la place ? Évidemment, passer du SQL au REST n'apporte rien, mais en supposant qu'il s'agisse d'un CRUD

46voto

Bunny Joel Points 43

Exiger SSL, garder SELinux activé, surveiller les journaux, et utiliser une version actuelle de PostgreSQL .

Côté serveur

Exiger SSL

En postgresql.conf set ssl=on et assurez-vous que votre fichier de clé et votre fichier de certificat sont installés de manière appropriée (voir la documentation et les commentaires dans le fichier postgresql.conf ).

Il se peut que vous deviez acheter un certificat auprès d'une autorité de certification si vous voulez qu'il soit reconnu par les clients sans configuration spéciale sur le client.

En pg_hba.conf utiliser quelque chose comme :

hostssl theuser thedatabase 1.2.3.4/32 md5

... éventuellement avec "tous" pour l'utilisateur et/ou la base de données, et éventuellement avec un filtre d'adresse IP source plus large.

Limiter le nombre d'utilisateurs qui peuvent se connecter, refuser la connexion du superutilisateur à distance.

N'autorisez pas "tout" pour les utilisateurs si possible ; vous ne voulez pas autoriser les connexions de superutilisateurs à distance si vous pouvez éviter d'en avoir besoin.

Limiter les droits des utilisateurs

Restreindre les droits des utilisateurs qui peuvent se connecter. Ne leur donnez pas CREATEDB o CREATEUSER droits.

REVOKE le site CONNECT à partir de PUBLIC sur toutes vos bases de données, puis le redonner aux seuls utilisateurs/rôles qui doivent pouvoir accéder à cette base de données. (Regroupez les utilisateurs en rôles et accordez les droits aux rôles, plutôt que directement aux utilisateurs individuels).

Assurez-vous que les utilisateurs ayant un accès distant ne peuvent se connecter qu'aux bases de données dont ils ont besoin et qu'ils n'ont des droits que sur les schémas, les tables et les colonnes dont ils ont réellement besoin. C'est également une bonne pratique pour les utilisateurs locaux, c'est une sécurité raisonnable.

Configuration du client

Dans PgJDBC, passez le paramètre ssl=true :

Pour demander au pilote JDBC d'essayer d'établir une connexion SSL, vous devez ajouter le paramètre ssl=true à l'URL de connexion.

... et installez le certificat du serveur dans le magasin de confiance du client, ou utilisez un certificat de serveur approuvé par l'une des autorités de certification du magasin de confiance intégré de Java si vous ne voulez pas que l'utilisateur ait à installer le certificat.

Action en cours

Maintenant s'assurer que vous maintenez PostgreSQL à jour . PostgreSQL n'a eu que quelques failles de sécurité préauth, mais c'est plus que zéro, alors restez à jour. Vous devriez de toute façon, les corrections de bogues sont des choses agréables à avoir.

Ajoutez un pare-feu en amont s'il y a de grands blocs de réseaux/régions dont vous savez que vous n'aurez jamais besoin d'y accéder.

Consigner les connexions et les déconnexions (voir postgresql.conf ). Enregistrez les requêtes si possible. Exécuter un système de détection d'intrusion ou fail2ban ou similaire en amont si possible. Pour fail2ban avec postgres, il existe un mode d'emploi pratique. ici

Surveillez les fichiers journaux.

Bonus paranoïa

Des étapes supplémentaires auxquelles il faut penser...

Exiger les certificats des clients

Si vous le souhaitez, vous pouvez également utiliser pg_hba.conf pour exiger que le client présente un certificat client X.509 reconnu par le serveur. Il n'est pas nécessaire d'utiliser la même autorité de certification que le certificat du serveur, vous pouvez le faire avec une autorité de certification openssl maison. Un utilisateur JDBC doit importer le certificat du client dans son Keystore Java avec keytool et éventuellement configurer certaines propriétés du système JSSE afin de diriger Java vers leur keystore, de sorte que ce n'est pas totalement transparent.

Mettre l'instance en quarantaine

Si vous voulez être vraiment paranoïaque, exécutez l'instance pour le client dans un conteneur / VM séparé, ou au moins sous un compte utilisateur différent, avec uniquement la ou les bases de données dont il a besoin.

De cette façon, s'ils compromettent l'instance PostgreSQL, ils n'iront pas plus loin.

Utiliser SELinux

Je ne devrais pas avoir à dire ça, mais...

Exécuter une machine avec un support SELinux comme RHEL 6 ou 7, et ne pas désactiver SELinux ou le mettre en mode permissif . Gardez-le en mode d'application.

Utiliser un port autre que celui par défaut

Sécurité par seulement l'obscurité est une stupidité. Une sécurité qui utilise un peu d'obscurité une fois que vous avez fait le nécessaire pour être raisonnable ne fera probablement pas de mal.

Exécutez Pg sur un port autre que celui par défaut pour rendre la vie un peu plus difficile aux attaquants automatiques.

Mettez un proxy devant

Vous pouvez également exécuter PgBouncer ou PgPool-II devant PostgreSQL, en agissant comme un pool de connexion et un proxy. De cette façon, vous pouvez laisser le proxy gérer SSL, et non le véritable hôte de la base de données. Le proxy peut être sur une VM ou une machine séparée.

L'utilisation de proxies de mise en commun des connexions est généralement une bonne idée avec PostgreSQL de toute façon, à moins que l'application cliente ait déjà un pool intégré. La plupart des serveurs d'application Java, Rails, etc. ont un pool intégré. Même dans ce cas, un proxy de mise en commun côté serveur est au pire inoffensif.

3 votes

Si le client a un $IP statique, autorisez-le uniquement à travers le pare-feu sur $port également.

0 votes

Merci beaucoup ! Pgjdbc a ce paramètre, mais je ne peux lui donner qu'une url de connexion jdbc, et je ne suis pas sûr que cela fonctionnera avec son application java (propriétaire, non débuggeable). Ok, si ce n'est pas le cas je poserai une nouvelle question. Merci pour votre réponse détaillée !

0 votes

@lain Il est toujours en mouvement, et cette application fonctionne sur son ordinateur portable... mais quoi qu'il en soit, merci !

2voto

peterh Points 4884

Une simple extension de l'impressionnant plan d'action de Craig :

Peut-être l'utilisateur n'utilise-t-il qu'un ensemble relativement restreint de fournisseurs de réseau (par exemple, son fournisseur de réseau mobile lorsqu'il déménage, son réseau câblé à domicile et l'adresse IP sortante de son lieu de travail).

La plupart des fournisseurs de réseaux ont de nombreuses IP, mais pas vraiment de sous-réseaux. Vous pouvez donc mettre en place un filtre iptables qui limite l'accès à postgresql aux segments de réseau utilisés par votre client. Cela réduit considérablement les possibilités d'attaque de sources de problèmes choisies au hasard sur le réseau.

Un scénario de soutien simple :

  1. Votre client vous appelle, "Je ne peux pas me connecter" .
  2. Vous le découvrez avec un tcpdump -i eth0 -p tcp port 5432 commande, d'où vient-il ?
  3. Avec un whois 1.2.3.4 vous pouvez obtenir l'adresse ip utilisée par cette ip. Par exemple, cela peut être 1.2.3.0/24 .
  4. Avec un iptables -A INPUT -s 1.2.3.0/24 -p tcp --dport 5432 -j ACCEPT (ou quelque chose de similaire) vous autorisez les connexions tcp avec son nouveau sous-réseau.

Il existe un très bon perl script nommé uif qui peut fournir des jeux de règles iptables déclarables permanents et intuitifs. (Google pour "uif iptables").

1 votes

Idée intéressante, mais qui semble un peu fragile.

0 votes

@nishantjr Bien sûr, il ne s'agit pas d'une solution autonome, mais seulement d'une possibilité d'améliorer les choses.

0 votes

Une approche plus pratique consisterait à établir une liste blanche de fournisseurs d'accès Internet et/ou de pays. stackoverflow.com/questions/16617607/

2voto

Josip Rodin Points 1510

Voici une configuration assez simple de Fail2ban pour PostgreSQL, basée sur le HOWTO mentionné ci-dessus, mais ajustée pour fonctionner avec les paquets Ubuntu, attraper une autre condition d'erreur et ignorer les divers messages de débogage afin d'accélérer le processus :

/etc/fail2ban/filter.d/local-postgresql.conf :

[Definition]

failregex = <HOST>\(\d+\) FATAL:  password authentication failed for .+$
            <HOST>\(\d+\) FATAL:  no pg_hba.conf entry for host .+$

ignoreregex = duration:

/etc/fail2ban/jail.d/local-postgresql.conf :

[local-postgresql]
enabled  = true
filter   = local-postgresql
action   = iptables[name=PostgreSQL, port=5432, protocol=tcp]
           sendmail-whois[name=PostgreSQL, dest=root@localhost]
logpath  = /var/log/postgresql/postgresql-9.3-main.log
maxretry = 3

2voto

metersales Points 21

Fail2ban est un outil puissant, mais ne croyez pas qu'un filtre fonctionnera tel quel. Testez tous les filtres à l'aide de la fonction outil failregex et n'oubliez pas d'échapper aux guillemets (par exemple, "admin" serait égal à \"admin\"). À titre d'exemple, le test de la ligne suivante du filtre failregex de mon /etc/log/postgresql/postgresql-9.3-main.log n'a pas fonctionné pour moi.

fail2ban-regex '2016-09-20 14:30:09 PDT FATAL:  password authentication failed for user "admin"' '<HOST>\(\d+\) FATAL:  password authentication failed for .+$'

Ce qui précède m'a donné

Failregex : 0 total

J'ai dû mettre à jour le failregex pour qu'il corresponde au format du journal.

fail2ban-regex '2016-09-20 14:30:09 PDT FATAL:  password authentication failed for user "admin"' 'FATAL:  password authentication failed for user \"<HOST>\"'

Cela m'a donné un résultat positif.

Failregex : 1 total

Le test fail2ban-regex peut également être mis en œuvre sur des fichiers journaux entiers.

fail2ban-regex /var/log/postgresql/postgresql-9.3-main.log /etc/fail2ban/filter.d/postgresql.local

Ce qui précède m'a donné le résultat positif suivant avec le failregex mis à jour.

Failregex : 169 au total

0 votes

+1 : mes logs sont en français, j'ai donc dû m'adapter. L'utilisation de fail2ban-regex a beaucoup aidé

1voto

Petr Přikryl Points 111

J'ai eu des problèmes pour configurer fail2ban en raison de l'absence d'adresse IP dans la configuration par défaut du journal PostgreSQL. J'utilise PostgreSQL 12 et 13 sur Debian 10. Si quelqu'un est confronté au même problème, voici comment le résoudre.

/etc/postgresql/13/main/postgresql.conf

log_line_prefix = '%m {%h} [%p] %q%u@%d '

La valeur par défaut était : '%m [%p] %q%u@%d ' . J'ai ajouté %h pour passer l'adresse IP à fail2ban.

/etc/fail2ban/filter.d/postgresql.conf

[Definition]
failregex = \{<HOST>\} .+? FATAL:  password authentication failed for user .+$

/etc/fail2ban/jail.d/postgresql.conf

[postgresql]

enabled = true
filter = postgresql
logpath = /var/log/postgresql/postgresql*.log
maxretry = 3
bantime = 86400
port = 5432

Puis redémarrez le service fail2ban systemctl restart fail2ban .

Et regardez les journaux tail -f /var/log/fail2ban.log .

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X