PostgreSQL dispose d'un support natif des connexions SSL pour chiffrer les connexions client/serveur en utilisant TLS pour améliorer ainsi la sécurité. Voir la Section 18.9 pour des détails sur la fonctionnalité SSL côté serveur.
libpq lit le fichier de configuration système
d'OpenSSL. Par défaut, ce fichier est nommé
openssl.cnf
et est placé dans le répertoire indiqué par
openssl version -d
. Cette valeur par défaut peut être
surchargée en configurant la variable d'environnement
OPENSSL_CONF
avec le nom du fichier de configuration
souhaité.
Par défaut, PostgreSQL ne vérifie pas le certificat du serveur. Cela signifie qu'il est possible de se faire passer pour le serveur final (par exemple en modifiant un enregistrement DNS ou en prenant l'adresse IP du serveur) sans que le client ne le sache. Pour empêcher cette usurpation (spoofing), le client doit être capable de vérifier l'identité du serveur via une chaîne de confiance. Une chaîne de confiance est établie en plaçant sur un ordinateur le certificat racine (auto-signé) d'une autorité de certification (CA), et sur un autre ordinateur un certificat feuille signé avec le certificat racine. Il est aussi possible d'utiliser un certificat « intermédiaire » signé par le certificat racine et qui signe des certificats feuilles.
Pour permettre au client de vérifier l'identité du serveur, placez un certificat racine sur le client et un certificat feuille signé par le certificat racine sur le serveur. Pour permettre au serveur de vérifier l'identité du client, placez un certificat racine sur le serveur et un certificat feuille signé par le certificat racine sur le client. Un ou plusieurs certificats intermédiaires (habituellement stockés avec le certificat feuille) peuvent aussi être utilisés pour lier le certificat feuille au certificat racine.
Une fois qu'une chaîne de confiance a été établie, il existe deux façons
pour le client de valider le certificat feuille envoyé par le serveur. Si
le paramètre sslmode
est configuré à
verify-ca
, libpq vérifiera qu'il peut faire confiance
au serveur en vérifiant
la chaîne des certificats jusqu'au certificat racine stocké sur le client.
Si sslmode
est configuré à
verify-full
, libpq va aussi
vérifier que le nom
d'hôte du serveur correspond au nom stocké dans le certificat du serveur.
La connexion SSL échouera si le certificat du serveur n'établit pas ces
correspondances. La connexion SSL échouera si le certificat du serveur ne
peut pas être vérifié. verify-full
est recommandé pour
les environnements les plus sensibles à la sécurité.
En mode verify-full
, le nom de l'hôte est mis en
correspondance avec le ou les attributs Subject Alternative
Name
(SAN) du certificat, ou avec l'attribut Common
Name
si aucun SAN de type dNSName
n'est
présent. Si le nom du certificat débute avec le caractère étoile
(*
), l'étoile sera traitée comme un métacaractère qui
correspondra à tous les caractères à l'exception du
point. Cela signifie que le certificat ne pourra pas correspondre à des
sous-domaines. Si la connexion se fait en utilisant une adresse IP au lieu
d'un nom d'hôte, l'adresse IP sera vérifiée (sans faire de résolution DNS)
avec les SAN de type iPAddress
ou
dNSName
. Si aucun SAN iPAddress
n'est
présent et qu'aucun SAN dNSName
correspondant n'est
présent, l'adresse IP de l'hôte est vérifié avec l'attribut Common Name.
Pour la compatibilité avec les anciennes versions de PostgreSQL, l'adresse
IP de l'hôte est vérifiée d'une façon différente à partir de RFC 6125. L'adresse IP
de l'hôte est toujours vérifiée avec avec les SAN
dNSName
ainsi qu'avec les SAN
iPAddress
et peut être vérifiée avec l'attribut Common
Name si aucun SAN n'existe.
Pour permettre la vérification du certificat du serveur, un ou plusieurs
certificats racines doivent être placés dans le fichier
~/.postgresql/root.crt
du répertoire personnel de
l'utilisateur (sur Windows, le fichier est nommé
%APPDATA%\postgresql\root.crt
). Les certificats
intermédiaires doivent aussi être ajoutés au fichier s'ils sont nécessaires
pour lier la chaîne de certificats envoyée par le serveur aux certificats
racines stockés sur le client.
Les entrées de la liste de révocation des certificats (CRL) sont aussi
vérifiées si le fichier ~/.postgresql/root.crl
existe
(%APPDATA%\postgresql\root.crl
sur Microsoft
Windows).
L'emplacement du certificat racine et du CRL peuvent être changés avec les
paramètres de connexion sslrootcert
et
sslcrl
, ou les variables d'environnement
PGSSLROOTCERT
et PGSSLCRL
.
sslcrldir
ou la variable d'environnement
PGSSLCRLDIR
peuvent aussi être utilisées pour indiquer un
répertoire contenant les fichiers CRL.
Par compatibilité avec les anciennes versions de
PostgreSQL, si un certificat racine d'autorité existe, le comportement
de sslmode
=require
sera identique
à celui de verify-ca
. Cela signifie que le
certificat du serveur est validé par l'autorité de certification. Il ne
faut pas se baser sur ce comportement. Les applications qui ont besoin
d'une validation du certificat doivent toujours utiliser
verify-ca
ou verify-full
.
Si le serveur tente de vérifier l'identité du client en réclamant le
certificat feuille du client, libpq enverra lse
certificats stockés dans le fichier
~/.postgresql/postgresql.crt
du répertoire personnel
de l'utilisateur. Les certificats doivent former une chaîne jusqu'au
certificat racine de confiance du serveur. Un fichier de
clé privé correspondant ~/.postgresql/postgresql.key
doit aussi être présent. Sur
Microsoft Windows, ces fichiers sont nommés
%APPDATA%\postgresql\postgresql.crt
et
%APPDATA%\postgresql\postgresql.key
.
L'emplacement des fichiers certificat et clé peut être surchargé par les
paramètres de connexion sslcert
et
sslkey
, ou par les variables d'environnement
PGSSLCERT
et PGSSLKEY
.
Sur les systèmes Unix, les droits sur le fichier de clé privée ne doit pas
permettre l'accès au monde et au groupe ; vous pouvez vous en assurer
avec une commande telle que chmod 0600
~/.postgresql/postgresql.key
. Il est aussi possible de rendre
root propriétaire deu fichier et d'avoir le droit d'accès pour le groupe
(autrement dit, les droits 0640
). Cette configuration est
prévue pour les installations où les fichiers certificat et clé sont gérés
par le système d'exploitation. L'utilisateur de
libpq devra alors devenir membre du group qui a
accès à ces fichiers certificat et clé. (Sur Microsoft Windows, aucune
vérification n'est effectuée sur les droits des fichiers car le répertoire
%APPDATA%\postgresql
est supposé sécurisé.)
Le premier certificat dans postgresql.crt
doit être le
certificat du client parce qu'il doit correspondre à la clé privée du
client. Les certificats « intermédiaires » peuvent être ajoutés
au fichier en option -- faire ainsi permet d'éviter d'avoir à stocker les
certificats intermédiaires sur le serveur (ssl_ca_file).
Le certificat et la clé doit être en format PEM ou ASN.1 DER.
La clé peut être stockée en clair dans le texte ou chiffrée avec un
passphrase utilisant un algorithme supporté par
OpenSSL, comme AES-128. Si la clé est stockée
chiffrée, alors la passphrase doit être fournie dans l'option de
connexion sslpassword. Si une clé
chiffrée est fournie et que l'option sslpassword
est
absente ou vide, une invite de saisie de mot de passe interactive par
OpenSSL s'affichera avec Enter PEM
pass phrase:
si un TTY est présent. Les applications peuvent
passer outre l'invite du certificat client et la gestion du paramètre
sslpassword
en fournissant leur propre callback pour
la clé du mot de passe, voir PQsetSSLKeyPassHook_OpenSSL
.
Pour des instructions sur la création de certificats, voir Section 18.9.5.
Les différentes valeurs du paramètre sslmode
fournissent
différents niveaux de protection. SSL peut fournir une protection contre trois types d'attaques différentes :
Si une tierce partie peut examiner le trafic réseau entre le client et le serveur, elle peut lire à la fois les informations de connexion (dont le nom de l'utilisateur et son mot de passe) ainsi que les données transmises SSL utilise le chiffrement pour empêcher cela.
Si une tierce partie peut modifier les données transitant entre le client et le serveur, il peut prétendre être le serveur et, du coup, voir et modifier les données y compris si elles sont chiffrées. La tierce partie peut ensuite renvoyer les informations de connexion et les données au serveur d'origine, rendant impossible à ce dernier la détection de l'attaque. Les vecteurs habituels pour parvenir à ce type d'attaque sont l'empoisonnement des DNS (DNS poisoning) et le détournement d'adresses (address hijacking), où le client est dirigé vers un autre serveur que celui attendu. Il existe encore plusieurs autres méthodes pour accomplir ceci. SSL utilise la vérification des certificats pour l'empêcher, en authentifiant le serveur auprès du client.
Si une tierce partie peut prétendre être un client autorisé, il peut tout simplement accéder aux données auquel il n'a pas droit. Typiquement, cela peut arriver avec une gestion incorrecte des mots de passe. SSL utilise les certificats clients pour empêcher ceci, en s'assurant que seuls les propriétaires de certificats valides peuvent accéder au serveur.
Pour qu'une connexion soit sûre, l'utilisation de SSL doit être configurée
sur le client et sur le serveur avant que
la connexion ne soit effective. Si elle n'est configurée que sur le serveur,
le client pourrait envoyer des informations sensibles (comme les mots de
passe) avant de savoir que le serveur exige une haute sécurité.
Dans libpq, les connexions sécurisées peuvent être garanties en
configurant le paramètre
sslmode
à verify-full
ou
verify-ca
, et en fournissant au système un certificat
racine à vérifier. Ceci est analogue à l'utilisation des URL
https
pour la navigation web chiffrée.
Une fois que le serveur est authentifié, le client peut envoyer des données sensibles. Cela signifie que, jusqu'à ce point, le client n'a pas besoin de savoir si les certificats seront utilisés pour l'authentification ne le spécifier que dans la configuration du serveur est donc sûr.
Toutes les options SSL impliquent une charge
supplémentaire sous forme de chiffrement et d'échange de clés.
Il y a donc un compromis à trouver entre performance et sécurité.
Tableau 32.1 illustre les risques que les
différentes valeurs
de sslmode
cherchent à protéger, et ce que cela apporte
en sécurité et fait perdre en performances.
Tableau 32.1. Description des modes SSL
sslmode | Protection contre l'écoute clandestine | Protection contre l'attaque MITM | Remarques |
---|---|---|---|
disable | Non | Non | Peu m'importe la sécurité, et je ne veux pas le coût apporté par le chiffrement. |
allow | Peut-être | Non | Peu m'importe la sécurité, mais je vais accepter le coût du chiffrement si le serveur insiste. |
prefer | Peut-être | Non | Peu m'importe le chiffrement, mais j'accepte le coût du chiffrement si le serveur le supporte. |
require | Oui | Non | Je veux chiffrer mes données, et j'en accepte le coût. Je fais confiance au réseau pour me garantir que je me connecterai toujours au serveur que je veux. |
verify-ca | Oui | Dépend de la politique de la CA | Je veux chiffrer mes données, et j'en accepte le coût. Je veux être sûr que je me connecte à un serveur en qui j'ai confiance. |
verify-full | Oui | Oui | Je veux chiffrer mes données, et j'en accepte le coût. Je veux être sûr que je me connecte à un serveur en qui j'ai confiance et que c'est bien celui que j'ai indiqué. |
La différence entre verify-ca
et verify-full
dépend de la politique de la CA racine. Si une
CA publique est utilisé, verify-ca
permet
les connexions à un serveur que quelqu'un d'autre a pu
enregistrer pour cette CA. Dans ce cas,
verify-full
devrait toujours être utilisé. Si une
CA locale est utilisée, voire un certificat auto-signé,
utiliser verify-ca
fournit souvent suffisamment de
protection.
La valeur par défaut pour sslmode
est prefer
.
Comme l'indique la table ci-dessus, cela n'a pas de sens d'un point de vue
de la sécurité, et ne promet, si elle possible, qu'un surcoût en terme
de performance.
Cette valeur est fournie par défaut uniquement pour la
compatibilité descendante, et n'est pas recommandée pour les déploiements de
serveurs nécessitant de la sécurité.
Tableau 32.2 résume les fichiers liés à la configuration de SSL sur le client.
Tableau 32.2. Utilisation des fichiers SSL libpq/client
Fichier | Contenu | Effet |
---|---|---|
~/.postgresql/postgresql.crt | certificat client | envoyé au serveur |
~/.postgresql/postgresql.key | clé privée du client | prouve le certificat client envoyé par l'utilisateur ; n'indique pas que le propriétaire du certificat est de confiance |
~/.postgresql/root.crt | autorités de confiance | vérifie que le certificat du serveur est signé par une autorité de confiance |
~/.postgresql/root.crl | certificats révoqués par les autorités de confiance | le certificat du serveur ne doit pas être sur cette liste |
Si votre application initialise les bibliothèques libssl
et/ou libcrypto
et que libpq
est construit avec le support de SSL, vous devez appeler
la fonction PQinitOpenSSL
pour indiquer à
libpq que les bibliothèques
libssl
et/ou libcrypto
ont été
initialisées par votre application, de façon à ce que
libpq n'initialise pas elle aussi ces
bibliothèques. Néanmoins, ceci n'est pas nécessaire lors de l'utilisation
d'OpenSSL version 1.1.0 ou supérieure, car les
initialisations dupliquées ne sont plus problématiques.
PQinitOpenSSL
#Permet aux applications de sélectionner les bibliothèques de sécurité à initialiser.
void PQinitOpenSSL(int do_ssl, int do_crypto);
Quand do_ssl
est différent de zéro,
libpq initialisera la bibliothèque
OpenSSL avant d'ouvrir une connexion à la base
de données. Quand do_crypto
est différent de
zéro, la bibliothèque libcrypto
sera initialisée. Par
défaut (si PQinitOpenSSL
n'est pas appelé), les deux
bibliothèques sont initialisées. Quand le support de SSL n'est pas
intégré, cette fonction est présente mais ne fait rien.
Si votre application utilise et initialise soit
OpenSSL soit libcrypto
,
vous devez appeler cette fonction avec des zéros
pour les paramètres appropriés avant d'ouvrir la première connexion à la
base de données. De plus, assurez-vous que vous avez fait cette
initialisation avant d'ouvrir une connexion à la base de données.
PQinitSSL
#Permet aux applications de sélectionner les bibliothèques de sécurité à initialiser.
void PQinitSSL(int do_ssl);
Cette fonction est équivalente à
PQinitOpenSSL(do_ssl, do_ssl)
. C'est suffisant pour les
applications qui initialisent à la fois OpenSSL
etlibcrypto
ou aucune des deux.
PQinitSSL
est présente depuis
PostgreSQL 8.0, alors que
PQinitOpenSSL
a été ajoutée dans
PostgreSQL 8.4, donc
PQinitSSL
peut être préférée pour les applications
qui ont besoin de fonctionner avec les anciennes versions de
libpq.