J'ai un gestionnaire qui aime "désactiver" les comptes en remplaçant le hachage bcrypt existant dans la base de données par un simple tiret (-
).
Cela semble fonctionner car l'ancien mot de passe n'est plus valide et il n'y a pas de hachage bcrypt valide auquel tout autre mot de passe pourrait correspondre. Mais j'étais curieux, est-ce efficace ou crée-t-il un risque pour la sécurité?
Est-ce un moyen efficace de faire en sorte qu'aucun mot de passe ne fonctionne ou crée-t-il un risque de sécurité plus important?
Cette implémentation spécifique utilise la fonction PHP password_verify mais j'aimerais que les réponses se concentrent sur toute implémentation générale. Veuillez ne pas vous concentrer sur les mauvaises pratiques de mon manager. Nous avons également un champ booléen pour définir l'utilisateur sur inactif/actif, ce qui, à mon avis, est meilleur et plus sûr, mais ce n'est pas ce sur quoi je veux que les réponses se concentrent.
En termes de refus des tentatives de connexion légitimes, ça va. À moins que vous n'utilisiez une fonction de hachage très bizarre, il n'y aura pas de valeurs mappées à -
, et il empêche les attaques par force brute contre les valeurs manquantes si la base de données est également volée, ce qui est positif (c'était peu probable, étant donné l'utilisation de bcrypt, mais cela s'applique même si l'implémentation utilise une méthode terrible pour stocker les mots de passe - à peu près tout autre chose que du texte brut).
En termes d'inconvénients, si la base de données est prise, cela diminue légèrement la sécurité des autres comptes - l'attaquant a moins d'enregistrements à utiliser brutalement. S'ils y prêtent attention, ils devraient probablement supprimer les enregistrements qui sont marqués comme inactifs, mais quand même. J'ai dit "légèrement" ...
Les autres risques pourraient être s'il existe des méthodes d'accès qui permettent de contourner la méthode de hachage pour la comparaison (par exemple, vous avez une méthode héritée qui permet de fournir le hachage complet pour une raison quelconque) - dans ce cas, si vous ne vérifiez pas l'actif soigneusement, il peut permettre l'accès en fournissant un tiret. Idéalement, supprimez cette méthode d'accès, si tel est le cas.
Un hachage de mot de passe invalide (généralement "*") désactive vraiment l'authentification par mot de passe, car il n'y a vraiment aucun moyen de lui fournir une valeur qui le hachera. Cependant, un hachage de mot de passe invalide ne "désactive pas" le compte s'il existe d'autres méthodes d'authentification, par ex. par clé privée ssh. En fait, il s'agit d'un moyen courant d'appliquer l'authentification par clé uniquement: un mot de passe non valide en combinaison avec une clé publique ssh dans ~user/.ssh
. Par conséquent, un hachage non valide dans la colonne de mot de passe ne doit pas être interprété comme "compte inactif", mais "authentification de mot de passe bloquée".
Si l'accès par mot de passe est le seul chemin disponible, un hachage non valide est sans doute supérieur au marquage explicite car il n'a pas besoin de support logiciel: si /etc/password
avait une colonne activeuser
et je l'ai utilisée en laissant un mot de passe valide dans le champ mot de passe, certains outils pourrait ignorer le champ activeuser
.
Une grande différence est certainement qu'un utilisateur marqué comme "inactif" peut toujours se connecter, sauf votre serveur vérifie l'indicateur et gère correctement la tentative. De plus, l'indicateur peut être supprimé, ce qui rétablit efficacement l'état d'origine, tout en changeant le hachage en "-" ne peut pas être restauré sans enregistrer le hachage du mot de passe ailleurs. En fonction de votre application, ce comportement peut ou non être souhaité.
Aucun risque de sécurité n'est créé par cette approche, car un attaquant ayant accès à votre base de données pourrait simplement voir que cet utilisateur n'est pas censé pouvoir se connecter. Comme vous l'avez correctement indiqué, aucun hachage bcrypt ne peut correspondre à "-", comme le format seul ne correspond pas.
Comme schroeder l'a déclaré dans les commentaires, ce n'est pas une mauvaise pratique, mais un concept courant pour empêcher les utilisateurs de se connecter, sans modifier le mécanisme de connexion pour prendre en compte votre indicateur "inactif" (les utilisateurs inactifs essayant de se connecter sont implicitement rejetés ).
Le but des hachages sécurisés est de rendre difficile le renforcement brutal des mots de passe dans la base de données. S'il est possible de déchiffrer, ou même de deviner, le mot de passe du "hachage simple", alors les mots de passe du compte sont en danger.
Mais ce n'est pas toute l'histoire. Si le but est simplement d'empêcher quiconque d'utiliser ou de deviner le mot de passe côté client, cela fonctionne très bien. Cette méthode est utilisée depuis longtemps. Mais les entrées de mot de passe à l'arrière sont affaiblies. Cela pourrait être très bien s'il existe d'autres contrôles et que les risques et les impacts de la compromission des comptes sont faibles.
Ceci est un autre dans la même veine que les autres réponses, alors permettez-moi d'abord de réitérer le point principal: cela peut être un moyen efficace d'invalider les utilisateurs tant qu'il n'y a pas d'autres moyens. À titre d'exemple à surveiller:
Comment votre système gère-t-il les utilisateurs connectés? Vraisemblablement, lorsqu'un utilisateur se connecte à votre système, il s'en souvient jusqu'à ce qu'il se déconnecte, probablement avec des cookies/sessions. Que stockez-vous dans la session pour vous assurer que votre utilisateur reste connecté? Plus important encore, que se passe-t-il si un utilisateur est connecté et que son hachage de mot de passe est invalidé? Si vous stockez le mot de passe lui-même dans la session, il sera effectivement déconnecté immédiatement, mais le stockage du mot de passe dans la session serait une mauvaise idée. Si vous stockez le hachage de mot de passe dans la session, ils seront également immédiatement déconnectés. Si toutefois, dans la session, vous enregistrez simplement le fait qu'ils sont connectés et l'ID de l'utilisateur sous lequel ils sont connectés, invalider le hachage ne déconnectera pas automatiquement les utilisateurs actuellement connectés. Je considérerais cela comme un problème, surtout si vous avez des sessions de longue durée. Que se passe-t-il si vous désactivez le hachage de quelqu'un et qu'une semaine plus tard, il ouvre son navigateur et est toujours connecté de toute façon? C'est pire si la fonction "Mettre à jour le mot de passe" que vous fournissez aux utilisateurs ne vous oblige pas à valider leurs anciens mots de passe. Dans ce cas, une personne déjà connectée peut rester connectée lorsque vous désactivez son hachage, puis pouvoir modifier son mot de passe et retrouver un hachage valide, en réactivant son compte.
Faites également attention aux clés API. Certains systèmes (Gitlab a obtenu un petit coup pour faire cela avant de changer leurs systèmes) ont des clés d'API de longue durée qui sont utilisées pour l'accès à l'API. Un utilisateur qui connaît sa clé API pourrait continuer à utiliser le système même si son hachage de mot de passe est modifié.
Étant donné le concept général de défense en profondeur, je voterais personnellement pour avoir une procédure de désactivation "formelle" dans votre système (je n'ai normalement qu'une colonne d'état dans la table utilisateur qui est vérifiée pendant le flux d'authentification/autorisation normal). Après tout, il peut y avoir de nombreuses mises en garde qui pourraient permettre à un utilisateur avec un hachage désactivé de pouvoir utiliser le système. Bien sûr, la sécurité est toujours une approche coût/bénéfice pour chaque entité, donc si l'ajout d'un indicateur de désactivation formel prend trop de temps pour votre système, et aucune des voies "d'attaque" dans les réponses ne vous semble applicable, alors vous êtes probablement bien.
Oui, c'est la manière standard sous Unix, et cela depuis des lustres.
La page de manuel shadow (5) répond explicitement à votre question:
If the password field contains some string that is not a valid
result of crypt(3), for instance ! or *, the user will not be
able to use a unix password to log in (but the user may log in
the system by other means).
Il existe des astuces supplémentaires, par exemple passwd (1) a une option --lock
:
-l, --lock
Lock the password of the named account. This option disables a
password by changing it to a value which matches no possible
encrypted value (it adds a ´!´ at the beginning of the password).
Note that this does not disable the account. The user may still
be able to login using another authentication token (e.g. an SSH
key). To disable the account, administrators should use usermod
--expiredate 1 (this set the account's expire date to Jan 2,
1970).
Users with a locked password are not allowed to change their
password.
La première chose à noter est qu'un "hachage de mot de passe" n'est pas simplement un hachage du mot de passe, c'est une structure multi-champs contenant non seulement le hachage lui-même mais une indication du schéma de hachage utilisé et des paramètres nécessaires (dans le cas de bcrypt un sel et un paramètre de coût)
Donc, la réponse à la question de savoir si un "hachage de mot de passe" invalide n'a aucun mot de passe de travail n'a rien à voir avec les fonctions de hachage, cela se résume à la façon dont le code de vérification gère les entrées qui ne représentent pas un hachage de mot de passe valide dans l'un des supports pris en charge formats. On pourrait espérer qu'il considérerait un hachage invalide comme non correspondant, mais la documentation n'est pas claire, nous devons donc lire la source.
https://github.com/php/php-src/blob/master/ext/standard/password.c
https://github.com/php/php-src/blob/master/ext/standard/crypt.c
En lisant le code de password_verify de php, nous le trouvons d'abord appelé "php_password_determine_algo", si le mot de passe commence par $ 2y $ il est considéré comme "bcrypt", s'il commence par "$ argon2i $" il est considéré comme étant argon2, sinon il est considéré comme "inconnu".
Si le hachage est "bcrypt" ou "inconnu", il passe ensuite à l'appel à php_crypt en lui passant le mot de passe et le hachage, cela tente de hacher le mot de passe fourni en utilisant la méthode et le sel du mot de passe existant, il peut le faire soit en utilisant un implémentation interne ou en appelant la fonction de cryptage du système d'exploitation. Il semble qu'étant donné un hachage existant non valide, le code interne reviendra au DES à l'ancienne, pas sûr de ce que l'implémentation du système fera.
En revenant à la section unknown/bcrypt dans password_verify, il semble qu'elle ne réussira pas à correspondre si l'une des conditions suivantes est vraie.
Votre hachage de "-" sera rejeté par au moins la règle 3 de cette liste (probablement aussi la règle 1 ou 2 mais cela dépend du comportement de l'implémentation de cryptage utilisée).