SASL est un cadre pour l'authentification dans des protocoles orientés connexions. Actuellement, PostgreSQL implémente trois mécanismes d'authentification SASL, SCRAM-SHA-256, SCRAM-SHA-256-PLUS et OAUTHBEARER. D'autres pourraient être ajoutés dans le futur. Les étapes ci-dessous illustrent comment l'authentification SASL est réalisé en général, alors que la sous-section suivante donne plus de détails sur ces mécanismes particuliers.
Flot de message d'authentification SASL
Pour commencer un échange d'authentification SASL, le serveur envoie un message AuthenticationSASL. Il inclut une liste des mécanismes d'authentification SASL que le serveur peut accepter, dans l'ordre de préférence du serveur.
Le client sélectionne un des mécanismes supportés dans la liste, et envoie
un message SASLInitialResponse au serveur. Le message inclut le nom du
mécanisme sélectionné, et un optionnel Initial Client
Response
, si le mécanisme sélectionné utilise cela.
Un ou plusieurs messages server-challenge
et
client-response
suivront. Chaque message
server-challenge
est envoyé dans un message
AuthenticationSASLContinue, suivi par une réponse d'un client dans un
message SASLResponse. Les particularités des messages sont spécifiques au
mécanisme.
Enfin, quand l'échange d'authentification est terminé avec succès, le serveur envoie un message AuthenticationSASLFinal optionnel, suivi immédiatement par un message AuthenticationOk. Le message AuthenticationSASLFinal contient des données supplémentaires du serveur au client, dont le contenu est spécifique au mécanisme d'authentification sélectionné. Si le mécanisme d'authentification n'utilise pas les données supplémentaires envoyées en fin, le message AuthenticationSASLFinal n'est pas envoyé.
En cas d'erreur, le serveur peut annuler l'authentification à tout moment, et envoie un message ErrorMessage.
SCRAM-SHA-256
, et sa variante avec liens entre canaux
SCRAM-SHA-256-PLUS
, sont des mécanismes
d'authentification basés sur les mots de passe. Ils sont décrits en détails
dans
RFC 7677
et RFC 5802.
Quand SCRAM-SHA-256 est utilisé dans PostgreSQL, le serveur ignorera le nom
d'utilisateur que le client envoie dans
client-first-message
. Le nom d'utilisateur qui
était déjà envoyé dans le message de démarrage est utilisé à la place.
PostgreSQL accepte plusieurs encodages de
caractères, alors que SCRAM impose l'utilisation d'UTF-8 pour le nom
d'utilisateur, donc il pourrait être impossible de représenter le nom
d'utilisateur PostgreSQL en UTF-8.
La spécification SCRAM impose que le mot de passe soit aussi en UTF-8, et soit traité avec l'algorithme SASLprep. Néanmoins, PostgreSQL ne requiert pas l'utilisation d'UTF-8 pour le mot de passE. Quand le mot de passe d'un utilisateur est configuré, il est traité avec SASLprep comme s'il était en UTF-8, quelque soit l'encodage réel. Néanmoins, s'il ne s'agit pas d'une séquence légale d'octets UTF-8 ou s'il contient des séquences d'octets UTF-8 qui sont interdites par l'algorithme SASLprep, le mot de passe brut sera utilisé sans le traitement de SASLprep, au lieu de renvoyer une erreur. Ceci permet au mot de passe d'être normalisé quand il est en UTF-8, en autorisant toujours l'utilisation d'un mot de passe non UTF-8, sans nécessiter que le système connaisse l'encodage du mot de passe.
La liaison de canal (Channel binding) est accepté par
PostgreSQL si ce dernier a été compilé avec le support de SSL. Le nom du
mécanisme SASL pour SCRAM avec liaison de canal est
SCRAM-SHA-256-PLUS
. Le type de liaison utilisé par
PostgreSQL est tls-server-end-point
.
Dans SCRAM sans liaison de canal, le serveur choisit un nombre aléatoire qui est transmis au client pour être mélangé avec le mot de passe fourni par l'utilisateur dans le hachage transmis du mot de passe. Bien que ceci empêche le hachage du mot de passe d'être retransmis avec succès dans une session ultérieure, cela n'empêche pas un faux serveur entre le serveur réel et le client de passer la valeur aléatoire du serveur et de s'authentifier avec succès.
SCRAM avec liaison de canal empêche ce type d'attaques man-in-the-middle en mélangeant la signature du certificat du serveur dans le hachage transmis du mot de passe. Bien qu'un faux serveur peut retransmettre le certificat du vrai serveur, il n'a pas accès à la clé privée correspondant à ce certificat et ne peut donc pas prouver qu'il en est le propriétaire, imposant de ce fait un échec de la connexion SSL.
Exemple
Le serveur envoie un message AuthenticationSASL. Il inclut une liste des
mécanismes d'authentification SASL que le serveur peut accepter. Ce sera
SCRAM-SHA-256-PLUS
et SCRAM-SHA-256
si le serveur dispose du support de SSL. Dans le cas contraire, ce sera
uniquement le dernier.
Le client répond en envoyant un message SASLInitialResponse, qui indique
le mécanisme choisi, SCRAM-SHA-256
ou
SCRAM-SHA-256-PLUS
. (Un client est libre de choisir un
mécanisme mais pour une sécurité plus forte, il devra choisir la variante
à liaison de canal s'il le gère.) Dans le champ Initial Client
response
, le message contient le message SCRAM
client-first-message
. Le message
client-first-message
contient aussi le type de
liaison de canal choisi par le client.
Le serveur envoie un message AuthenticationSASLContinue, avec un message
SCRAM server-first-message
comme contenu.
Le client envoie un message SASLResponse, avec le message SCRAM
client-final-message
comme contenu.
Le serveur envoie un message AuthenticationSASLFinal, avec le message
SCRAM server-final-message
, suivi immédiatement
par un message AuthenticationOk.
OAUTHBEARER
est un mécanisme basé sur un jeton pour une
authentification fédérée. Il est décrit en détails dans la
RFC 7628.
Un échange typique diffère suivant si le client a déjà un jeton en cache pour l'utilisation actuel. Si ce n'est pas le cas, l'échange se fera sur deux connexions : la première connexion « de découverte » pour obtenir les méta-données OAuth du serveur, et la deuxième connexion pour énvoyer le jeton après que le client l'ait obtenu. (libpq n'implémente pas actuellement une méthode de cache, donc il utilise l'échange à deux connexions.)
Ce mécanisme est initié par le client, comme SCRAM. La réponse initiale
du client consiste en l'en-tête standard GS2 utilisé par SCRAM, suivi par
une liste de paires clé=valeur
. La seule clé actuellement
supportée par le serveur est auth
, qui contient le jeton
du porteur. OAUTHBEARER
spécifie en plus trois composants
optionnels de la réponse initiale du client (le authzid
de l'en-tête GS2, et les clés host
et
port
) qui sont actuellement ignorés par le
serveur.
OAUTHBEARER
n'accepte pas le channel
binding, et il n'y a pas de mécanisme
« OAUTHBEARER-PLUS ». Ce mécanisme n'utilise pas les données du
serveur lors d'une authentification réussie, donc le message
AuthenticationSASLFinal message n'est pas utilisé dans l'échange.
Exemple
Lors du premier échange, le serveur envoie un message AuthenticationSASL
avec le mécanisme OAUTHBEARER
indiqué.
Le client réponds en envoyant un message SASLInitialResponse qui indique
le mécanisme OAUTHBEARER
. En supposant que le client
n'a pas déjà un jeton du porteur valide pour l'utilisateur actuel, le
champ auth
est vide, indiquant une connexion
de découverte.
Le serveur envoie un message AuthenticationSASLContinue contenant un
statut
d'erreur avec une URI bien connue et les portées
que le client doit utiliser pour conduire un flux OAuth.
Le client envoie un message SASLResponse contenant l'ensemble vide (un
seul octet 0x01
) pour finir sa moitié de l'échange de
découverte.
Le serveur envoie un ErrorMessage pour faire échouer le premier échange.
À ce moment, le client conduit un flux parmi différents flux OAuth
possibles pour obtenir un jeton du porteur, en utilisant toutes les
métadonnées avec lesquelles il a été configuré, en plus de celles fournies
par le serveur. (Cette description est laissée vague délibérément ;
OAUTHBEARER
n'indique pas ou ne réclame pas de
méthodes particulières pour obtenir un jeton.)
Une fois qu'il a un jeton, le client se reconnecte au serveur pour l'échange final :
Le serveur envoie de nouveau un message AuthenticationSASL avec le
mécanisme OAUTHBEARER
indiqué.
Le client réponds en envoyant un message SASLInitialResponse, mais cette
fois, le champ auth
dans le message contient
le jeton du porteur qui a été obtenu lors du flux du client.
Le serveur valide le jeton en suivant les instructions du fournisseur de jeton. Si le client est autorisé à se connecter, il envoie un message AuthenticationOk pour terminer l'échange SASL.