Flexible Security for Your Peace of Mind

Remise à zéro de l’horloge pour l’expiration de mot de passe Active Directory

J’ai récemment travaillé avec un client qui mettait en œuvre Specops Password Policy avec l’expiration des mots de passe basé sur la longueur. En général, les clients utilisent cette fonction pour prolonger l’âge maximal de leurs mots de passe. Par exemple, l’âge maximal actuel des mots de passe dans Active Directory est de 90 jours ; l’expiration basée sur la longueur de Specops sera configuré avec le même âge maximal des mots de passe de « niveau 1 », mais les utilisateurs qui choisissent d’aller au-delà de la longueur minimale requise peuvent conserver leur mot de passe beaucoup plus longtemps que cela.

Ce client, contrairement à la plupart des autres, avait déjà un âge maximal de 180 jours pour les mots de passe dans Active Directory, mais il voulait mettre en œuvre Specops de telle sorte que les mots de passe plus courts soient toujours autorisés ; cependant, si les utilisateurs choisissent de continuer à les utiliser, ils verraient maintenant l’âge maximal de leur mot de passe réduit de 180 jours à 90 jours.

C’est une bonne stratégie pour guider les utilisateurs à choisir des mots de passe plus longs sans les forcer, mais la mise en œuvre a présenté un défi : avec Specops Password Policy, l’expiration des mots de passe basée sur la longueur n’est calculée qu’au premier changement de mot de passe après la mise en œuvre de la politique Specops. Étant donné qu’Active Directory stocke un mot de passe haché et que les hachages ont toujours la même longueur, quelle que soit la longueur du mot de passe, nous ne disposons d’aucune information pour récompenser les utilisateurs qui utilisent des mots de passe plus longs dès le premier jour. Ainsi, lors de la mise en œuvre d’une politique comme celle décrite ci-dessus, tous les mots de passe actuels devront expirer après le seuil de niveau 1 de 90 jours avant que l’expiration basé sur la longueur puisse prendre effet. Le problème pour ce client est qu’un grand pourcentage de ses utilisateurs ont déjà des mots de passe vieux de 90 à 180 jours et que ces utilisateurs verraient tous leurs mots de passe expirer le jour de la mise en œuvre de Specops Password Policy.

Pour soulager les utilisateurs finaux et le service d’assistance qui pourraient être confrontés à une vague soudaine d’expirations de mots de passe, nous avons trouvé un moyen de prolonger l’âge du mot de passe actuel des utilisateurs sans modifier la configuration de la politique. Pour ce faire, nous avons exploité un comportement inhabituel mais voulu d’Active Directory.

L’attribut PwdLastSet et la demande de changement de mot de passe à la prochaine connexion

Chaque compte utilisateur possède un attribut appelé pwdLastSet. Cet attribut est écrit par Active Directory avec l’horodatage actuel chaque fois que le mot de passe de l’utilisateur est modifié ou réinitialisé.  Nous pouvons inspecter cet attribut dans l’onglet d’attributs AD Users and Computers ou en utilisant le module ActiveDirectory PowerShell :

get-aduser username -properties pwdlastset,passwordlastset | fl samaccountname,pwdlastset,passwordlastset

Note : Avec PowerShell, nous devons interroger l’attribut passwordLastSet et non pwdLastSet pour obtenir une valeur lisible – pwdLastSet renvoie le résultat au format filetime ; vous pouvez convertir cette valeur en un DateTime lisible mais il est beaucoup plus facile d’interroger passwordLastSet et de laisser AD/PowerShell faire la conversion pour vous.

Active Directory et Specops Password Policy calculent tous deux l’expiration des mots de passe en fonction de l’attribut pwdLastSet. Si l’horodatage pwdLastSet + le maxPasswordAge en jours est une date qui tombe dans le passé, le mot de passe de l’utilisateur expirera et il sera obligé de le changer à la prochaine connexion. Un administrateur ne peut pas écrire un horodatage différent dans cet attribut, ni effacer directement la valeur de cet attribut. En revanche, l’administrateur ne peut pas effacer l’attribut en l’écrivant directement.

Voyons ce qui se passe lorsque nous cochons la case indiquant que l’utilisateur doit changer son mot de passe à la prochaine connexion :

Maintenant, inspectons la valeur de l’attribut pwdLastSet :

get-aduser username -properties pwdlastset,passwordlastset | fl samaccountname,pwdlastset,passwordlastset

Il n’y a en fait aucun attribut sur un compte d’utilisateur qui corresponde à la case à cocher « l’utilisateur doit changer son mot de passe à la prochaine connexion ». Au lieu de cela, Active Directory définit la valeur de pwdLastSet à 0, ce qui donne l’impression que le mot de passe de l’utilisateur n’a jamais été défini. Cela simplifie le code qui, ailleurs, calcule si le mot de passe d’un utilisateur a expiré : si le mot de passe de l’utilisateur n’a jamais été défini, il a toujours été défini il y a plus de maxPasswordAge jours et doit donc être changé à la prochaine connexion !

Maintenant, que se passe-t-il si nous revenons en arrière et décochons cette case ?  Que devient l’attribut pwdLastSet ?

get-aduser username -properties pwdlastset,passwordlastset | fl samaccountname,pwdlastset,passwordlastset

Si le fait de cocher la case « l’utilisateur doit changer son mot de passe à la prochaine connexion » donne la valeur 0 à l’attribut pwdLastSet, lorsque l’on décoche cette case, AD doit écrire autre chose à cet endroit. Il ne peut pas revenir à l’heure réelle à laquelle le mot de passe a été défini pour la dernière fois (puisque cette information a été effacée lorsque la case a été cochée). Il écrit donc l’heure actuelle, comme il le ferait lors d’un changement de mot de passe. Vous pouvez voir ici la date et l’heure exactes que j’ai testées pour écrire cet article de blog.

Nous pouvons convenir que ce comportement semble un peu étrange, et qu’il pourrait potentiellement fournir une échappatoire aux administrateurs pour laisser les mots de passe durer plus longtemps qu’ils ne le devraient (ce qui est vrai), mais mon client a eu la brillante idée d’utiliser ce comportement à son avantage. En cochant et décochant la case « l’utilisateur doit changer son mot de passe à la prochaine connexion » pour chaque utilisateur, il pouvait en fait remettre à zéro l’horloge d’expiration du mot de passe lors du déploiement de la  Specops Password Policy. Tous les utilisateurs pouvaient conserver leur mot de passe existant jusqu’à 90 jours à partir du moment où cela était fait conformément à sa nouvelle politique de mot de passe Specops ; tous les utilisateurs qui n’ont pas profité de l’avertissement préalable seraient tenus de changer leur mot de passe 90 jours plus tard.

Bien sûr, personne ne suggère de faire cela manuellement pour une grande base d’utilisateurs, nous avons donc écrit quelques scripts PowerShell qui le feront pour nous.

Le premier consiste à remplir un tableau $users avec les utilisateurs que nous voulons cibler.  Pour effectuer cette opération sur la base d’une OU, nous définissons $targetOU comme le nom distinctif de l’OU souhaité :

$targetOU = "OU=Demo,OU=Users,OU=Specops,DC=specopsdemo1,DC=com"
$users = get-aduser -searchbase $targetOU -filter { passwordNeverExpires -eq $false -and pwdLastSet -gt 0 } -properties passwordLastSet

Pour cibler à la place tous les membres d’un groupe de sécurité indépendamment de l’OU dans lequel ils se trouvent :

$targetGroup = "GroupName"
$users = Get-ADGroupMember -recursive $targetGroup | get-aduser -Properties passwordneverexpires,passwordlastset | Where-Object { $_.passwordNeverExpires -eq $false -and $_.passwordLastSet }

Notez que dans la sélection, nous excluons les utilisateurs pour lesquels le paramètre ‘Password Never Expires’ est défini (vous ne pouvez pas définir l’option ‘require change at next logon’ pour ces utilisateurs) ainsi que les utilisateurs qui doivent déjà changer leur mot de passe à la prochaine connexion, car nous imaginons qu’il peut y avoir une bonne raison pour cela.

Après avoir exécuté la requête de sélection préférée, vous pouvez simplement taper $users et appuyer sur entrée pour confirmer votre sélection.

Pour activer ou désactiver l’option de changement de mot de passe à la prochaine connexion, exécutez le bloc de code suivant :

foreach ($user in $users) {
    $outObject = new-object -typename psobject
    $outobject | Add-member -MemberType NoteProperty -Name distinguishedName -Value $user.distinguishedname
    $outobject | Add-Member -MemberType NoteProperty -Name OldPasswordLastSet -value $user.passwordlastset
    set-aduser $user -ChangePasswordAtLogon:$true
    set-aduser $user -ChangePasswordAtLogon:$false
    $outobject | Add-Member -MemberType NoteProperty -Name NewPasswordLastSet -value $(get-aduser $user -Properties passwordlastset).passwordlastset
    $outObject
} 

Le script active et désactive l’option un utilisateur à la fois et affiche les utilisateurs au fur et à mesure qu’ils sont traités, y compris les anciennes et nouvelles valeurs de passwordLastSet.  Si l’ancienne valeur est vide, cela signifie que l’attribut passwordLastSet était déjà défini à 0/never.

Voici un exemple d’exécution du script dans un OU cible dans l’ISE PowerShell :

Et plutôt dans un groupe cible :

(Dernière mise à jour le 24/11/2021)

Revenir sur le blog