Authentification à deux facteurs (OTP) partout… ou presque

De nos jours, tout le monde vante l'authentification multi-facteurs comme la solution à tous les maux du phishing. À y regarder de plus près, chaque constructeur, chaque éditeur de logiciel, etc. fournit sa solution d'authentification forte. Par exemple, sur les équipements réseau, chaque éditeur impose son autorité de certification si on veut authentifier les accès à privilèges par certificat X.509. Ça n'est pas viable si on veut s'épargner la gestion d'une autorité de certification.

Il existe des solutions d'authentification forte normalisées et sûres comme FIDO ou OATH. Heureux propriétaire de YubiKey depuis presque dix ans, je n'utilisais jusqu'à il y a peu que HMAC-SHA1 et OpenPGP mais j'utilise de plus en plus FIDO (clefs SSH) et surtout OATH TOTP.

Commençons par TOTP : il s'agit de Time-based One Time Password c'est à dire mot de passe à usage unique basé sur le temps : l'horloge fait varier le mot de passe. L'algorithme est spécifié dans la RFC 6238 ; il est décrit dans Mot de passe à usage unique basé sur le temps et utilise un secret partagé (20 octets aléatoires), stocké sur un serveur et dans la YubiKey. L'échange de secrets se fait par une URI OATH détaillée sur cette page, URI souvent échangée par QR code.

NB : évidemment, il faut synchroniser les horloges, NTP sert à ça.

Depuis la version 2.5 d'OpenLDAP, est intégré (cf. bug #9437) slapo-otp(5). Ce module intègre un schéma ad hoc pour stocker des clefs TOTP en plus du mot de passe userPassword. Il suffit de charger le module binaire.

Soit une politique (l'OID 1.2.840.113549.2.7 définit HMAC-SHA1) :

dn: cn=oathtokens,ou=policies,dc=example,dc=com
objectClass: top
objectClass: person
objectClass: oathTOTPParams
cn: oathtokens
sn: oathtokens
oathOTPLength: 6
oathHMACAlgorithm: 1.2.840.113549.2.7
oathTOTPTimeStepPeriod: 30
oathTOTPTimeStepWindow: 3
structuralObjectClass: person

Ajoutons maintenant à un posixAccount les attributs suivants :

dn: uid=jdoe,ou=people,dc=example,dc=com
objectClass: posixAccount
...
oathSecret:: A3ag...d17I=
oathTOTPParams: cn=oathtokens,ou=policies,dc=example,dc=com
oathTokenSerialNumber: 19201802
oathTOTPToken: uid=jdoe,ou=people,dc=example,dc=com

oathSecret contient le secret partagé encodé en base64 (ici oathSerialNumber contient le numéro de série du jeton YubiKey, c'est purement optionnel).

Lorsque jdoe s'authentifie, il saisit son mot de passe suivi des six chiffres donnés par sa « calculatrice OATH » (un script, une application comme Yubico Authenticator, …). Par exemple monpasswordamoiquejai123456.

Ainsi, toutes les applications dont l'authentification est adossée à cet annuaire offrent maintenant une authentification à deux facteurs pour ce DN : accès RADIUS aux équipements réseau, applications web diverses et variées, pam_ldap, bref tout ce qui repose sur LDAP.

NB : si les entrées oath* sont supprimées, seul son mot de passe stocké dans userPassword est requis.

MinTOTP propose en quelques lignes de Python une « calculatrice TOTP ». Il ne manque plus qu'un peu de glue code pour :

  • générer le secret partagé
  • l'enregistrer au bon format dans l'annuaire
  • le présenter à l'utilisateur sous forme de QR code (qrcode)

NB : sur OpenBSD, le module login_totp-and-pwd(8) permet lui aussi une authentification à deux facteurs avec OATH TOTP. Par contre, il faut saisir 123456/password et non pas password123456 ie. dans l'ordre inverse et avec un / entre les deux.

Pour finir, rappelons que le secret TOTP peut être stocké dans un jeton USB comme une YubiKey mais aussi dans un gestionnaire de mots de passe sérieux comme Keepass (ou une variante compatible) ou encore FreeOTP.

  • blog/ldap-2fa.txt
  • Dernière modification : 2023/04/16 15:58
  • de pc