Disclaimer Je ne suis pas un professionnel de la sécurité, juste un programmeur essayant de faire de mon mieux. De plus, c'est mon premier message à cette communauté, donc je m'excuse si cette question est trop large.
La situation Mon réseau local (géré et sécurisé par une équipe informatique professionnelle) possède de nombreux appareils exécutant de simples serveurs Web qui servent des pages utilisées pour contrôler les enregistreurs de données, les contrôleurs PID, etc. Ces pages Web ont actuellement aucune forme d'authentification du tout, ce qui sera un gros problème si un mauvais acteur compromet le réseau.
Mon objectif consiste à ajouter une authentification à ces pages Web en ajoutant une page de connexion à l'application exécutée par le serveur. (Peut-être pertinent, j'utilise Python pour exécuter le serveur.)
My Implementation J'ai une conception de preuve de concept dans laquelle je fais ce qui suit:
(Notez que toutes les communications entre la page Web et le serveur utilisent POST.)
Questions et préoccupations:
Les meilleures pratiques générales actuelles pour l'authentification se trouvent dans le NIST SP 800-63-3 Digital Identity Guidelines , en particulier dans SP-63B Authentication and Lifecycle Gestion .
Ces normes NIST sont faciles à lire pour les développeurs, et en plus de vous dire quoi faire, elles parlent également de pourquoi vous voulez faire certaines choses. (Si vous souhaitez plus de détails que les normes NIST, nous sommes heureux de vous aider.)
Cela dit, examinons votre système d'authentification actuel et répondons à vos préoccupations:
L'utilisateur est invité à entrer son nom d'utilisateur et son mot de passe sur la page d'inscription
La page inscription?
Il s'agit probablement d'une faute de frappe et vous vouliez dire une page de connexion, mais s'il y a une page d'enregistrement à laquelle n'importe qui sur votre réseau peut accéder, vous devez définir explicitement un système séparé autorisation. Par exemple, n'importe qui peut créer un compte sur n'importe quelle boutique en ligne, mais ce compte ne vous donne pas accès à la partie de leur site qui permet aux administrateurs de modifier les prix de leurs produits.
Le serveur hache le mot de passe à l'aide de SHA256 pour créer des hachages de longueur égale
Cette étape n'ajoute aucune sécurité ni n'améliore les performances du système de manière significative, d'autant plus que vous utilisez bcrypt, qui supprimera de toute façon toute partie du mot de passe après les 72 premiers caractères.
C'est peu probable, mais cette étape pourrait réduire l'entropie. La réduction de l'entropie est insignifiante dans le grand schéma des choses et nécessite que les utilisateurs utilisent déjà des mots de passe longs et générés de manière aléatoire, mais comme il s'agit d'une étape supplémentaire qui n'améliore pas la sécurité, je suggère de la laisser de côté.
Un sel aléatoire est généré en utilisant un facteur de travail raisonnable.
J'avoue que j'étais très confus de voir cette étape au début. S'il s'agissait de l'entretien de la voiture, cela aurait autant de sens pour moi que "l'huile synthétique ajoutée avec un indice d'octane raisonnable". Cependant, dans les commentaires, il a été révélé que la bibliothèque bcrypt spécifique utilisée est la bibliothèque bcrypt hébergée par PyPI .
Je ne trouve pas le code source (et je suis allergique aux langages qui utilisent des espaces pour délimiter la portée), mais d'après la documentation, il semble que l'appel de fonction de la bibliothèque pour générer les paramètres de bcrypt s'appelle bcrypt.gensalt(workfactor)
, et cette méthode elle-même prend un facteur de travail comme paramètre ... Etendre la métaphore de l'entretien de la voiture, ce serait comme s'il y avait une fonction nommée vehicle.refuel(viscosity)
, ou vehicle.changeoil(octane)
.
Un sel, dans le jargon d'authentification et de cryptographie, est une valeur aléatoire qui est ajoutée à un texte en clair, pour qu'il soit impossible de pré-calculer la sortie d'une fonction de hachage cryptographique ou d'une fonction de dérivation de clé. Le sel lui-même n'est pas un secret; sa seule force est qu'elle n'est pas connue à l'avance.
La valeur d'un sel est mesurée en combien de temps il est, également appelé son entropie. (L'entropie en cryptographie est un sujet nuancé, qui dépend de plus que de la longueur, mais pour toute bibliothèque raisonnable qui crée un sel, plus le sel est long, plus il a d'entropie.)
Un facteur de travail, d'autre part, est le jargon qui est spécifique aux algorithmes d'étirement des clés, comme ce bcrypt KDF. Le facteur de travail définit la quantité de travail que le processeur (ou GPU, FPGA ou ASIC lorsque vous êtes l'attaquant) doit faire, et sa principale caractéristique est qu'il faut plus de temps pour calculer la sortie , en utilisant des étapes qui ne peuvent pas être contournées, devinées ou ignorées. Cela peut sembler contre-intuitif; vous voulez que votre application s'exécute le plus rapidement possible, non?
Eh bien, le risque général est que votre base de données de mots de passe soit divulguée. Les meilleurs détaillants divulguent des mots de passe tout le temps, et vous n'avez pas les millions de dollars à dépenser pour sécuriser des applications comme le font les meilleurs détaillants, alors supposez que votre base de données de mots de passe pourrait éventuellement être divulguée également.
Le compromis ici est que, lors de la connexion, votre utilisateur devra attendre une seconde supplémentaire. Lorsqu'un attaquant déchiffre vos mots de passe, il ne peut deviner qu'un seul mot de passe par seconde, par CPU qu'il met à la tâche. (Les attaquants motivés peuvent prendre certains raccourcis, mais même 10 suppositions par seconde sont BEAUCOUP mieux que des milliards de suppositions par seconde si vous utilisez simplement SHA256 en un seul tour au lieu d'un algorithme d'étirement des touches.)
Ainsi, le sel et le facteur de travail sont deux paramètres importants qui n'ont rien à voir l'un avec l'autre. Je suis désolé que votre première exposition au concept ait eu lieu à travers une fonction très mal nommée.
Le mot de passe haché est haché à nouveau, cette fois avec le sel. (La génération de sel et le hachage utilisent le bcrypt de python)
Petite piqûre, mais c'est parce que je suis minutieux: les résultats de bcrypt ne sont pas un hachage, même si beaucoup de gens l'appellent un hachage, et tout le monde ici saura de quoi vous parlez si vous continuez à l'appeler un hacher. Les résultats sont un mot de passe étiré ou une clé dérivée.
Le nom d'utilisateur, le facteur de travail, le sel et le hachage sont stockés dans la base de données de mots de passe.
Si le résultat ressemble à ceci, vous disposez déjà du facteur de travail, du sel et de la clé dérivée:
$2a$08$0SN/h83Gt1jZMR6924.Kd.HaK3MyTDt/W8FCjUOtbY3Pmres5rsma
Le 2a
est l'algorithme (bcrypt avec prise en charge unicode).
Le 08
est le facteur de travail.
Les 22 caractères suivants, 0SN/h83Gt1jZMR6924.Kd.
, sont le sel.
Et le reste est la clé dérivée.
Si vous obtenez quelque chose de différent de votre bibliothèque bcrypt, trouvez une autre bibliothèque.
Lorsqu'un utilisateur tente de se connecter, le mot de passe saisi est haché de la même manière et comparé à l'enregistrement dans la base de données. (Le sel utilisé pour la comparaison est extrait de la base de données de mots de passe en utilisant le nom d'utilisateur entré comme clé.)
Génial. Cependant, la bibliothèque que vous utilisez fait déjà le gros du travail pour vous, alors utilisez votre bibliothèque au maximum. Le bcrypt.checkpw
la fonction extraira pour vous le facteur de travail, le sel et la clé dérivée. Il exécutera ensuite son KDF et comparera les résultats.
L'utilisation de cette fonction de bibliothèque signifie que, si vous décidez de modifier le facteur de travail par défaut à l'avenir, vous n'avez pas besoin d'avoir un code séparé pour gérer les anciennes clés dérivées, comme bcrypt.checkpw
pourra déterminer seul le facteur de travail souhaité.
Si les hachages correspondent, un cookie est donné à l'utilisateur qui lui donne accès aux pages Web restreintes.
Cela sonne bien à première vue ... mais assurez-vous que le cookie lui-même ne contient pas l'autorisation. Il doit contenir une chaîne générée aléatoirement (ID de session) et lors de l'accès au site, le serveur doit regarder cet ID de session et vérifier ses propres ressources pour voir si cet ID de session est correctement autorisé. Nettoyez également les ID de session après un certain temps.
Si votre cookie contient "is_authorized = true" au lieu d'un ID de session où le serveur vérifie ses propres ressources, les utilisateurs peuvent simplement créer leurs propres cookies d'autorisation et n'auront jamais besoin de s'authentifier.
Préoccupations:
Enregistrer le hachage, le facteur de travail et le sel dans la même base de données semble être une mauvaise pratique.
Les facteurs sel et travail ne sont en aucun cas sensibles, mais sont nécessaires pour valider un mot de passe. Au mieux, toute tentative de cacher le sel entraînera une sécurité à travers l'obscurité, ce qui n'est pas du tout une sécurité. Vous pourriez aussi bien stocker le facteur de travail et le sel juste à côté de la clé dérivée, pour vous éviter le mal de tête, car les diviser ne va pas empêcher un attaquant de les atteindre.
Cette méthode de hachage garantit-elle (raisonnablement) que personne ne peut déterminer le mot de passe d'un utilisateur, y compris moi-même?
En ce qui concerne votre responsabilité en tant que développeur web? Oui.
Et merci d'avoir demandé si cela raisonnablement garantit que personne ne peut déterminer un mot de passe. Ils peuvent toujours être devinés dans les attaques hors ligne, mais l'utilisation d'un algorithme d'étirement des clés tel que bcrypt gênera considérablement les attaquants, même dans le pire des cas d'une attaque hors ligne contre une base de données divulguée.
La seule chose que vous pouvez faire de mieux est d'ajouter 2fa et d'exiger que vos utilisateurs utilisent des gestionnaires de mots de passe avec des mots de passe véritablement aléatoires de 24 caractères et plus, uniques pour chaque site.
Notez que les réinitialisations de mot de passe ne doivent pas dépendre seulement de ce deuxième facteur. Selon les directives du NIST, cela devrait dépendre des mêmes facteurs d'identification utilisés dans la configuration du compte en premier lieu (et faire autant de bruit que possible sur autant de canaux de communication utilisateur que votre application en connaît) et utiliser au moins un facteur supplémentaire, s'il est disponible.
Pour la plupart des applications Web, cela signifie un e-mail au compte utilisé lors de l'enregistrement du compte ( [~ # ~] et non [~ # ~] des messages texte à un téléphone portable, ou des questions de sécurité en soi, bien que cela puisse être des facteurs supplémentaires après l'e-mail est envoyé). Pour une application métier interne, cela signifie que l'utilisateur doit faire un appel à l'équipe sysops/helpdesk (ou, plus réaliste, il doit s'arrêter au bureau du développeur).
Tout utilise actuellement http. Https est-il nécessaire si tous les accès se trouvent sur le réseau local?
Vous devez faire confiance à votre réseau local dans une certaine mesure. Cependant, cela ne fait jamais de mal d'ajouter HTTPS. Si vous êtes inquiet, ajoutez HTTPS. (Le fait que vous ayez posé ces questions signifie que, oui, vous êtes inquiet. Alors oui, vous devez ajouter HTTPS.)
L'ajout de HTTPS est également une bonne idée pour des raisons non liées à la sécurité, car les serveurs Web (et les navigateurs) utiliseront HTTP/2, si disponible, uniquement via des connexions HTTPS. Cela peut accélérer considérablement votre site. Cela ne s'applique pas dans votre cas, car vous utilisez un serveur Web basé sur un script Python, qui a peu de chances d'avoir des capacités HTTP/2, mais c'est une bonne habitude d'entrer pour des raisons au-delà de la "simple" sécurité. (La sécurité est plus que suffisante à mon avis, mais il y a des managers qui ont besoin de plus de conviction.)
L'utilisation d'un cookie est-elle un bon moyen de vérifier qu'un utilisateur s'est correctement connecté?
Si ce cookie contient un ID de session plutôt que des informations d'authentification, cet ID de session est aléatoire et le serveur vérifie l'ID de session, alors oui. Il s'agit d'une pratique standard pour la grande majorité des sites Web disposant de tout type d'identification d'utilisateur.
Le sel n'est pas censé être secret. Son but est d'être différent pour chaque mot de passe, donc la base de données hachée ne peut pas être attaquée avec des tables Rainbow. Les autres paramètres que vous mentionnez ne sont pas non plus censés être secrets. Vous pouvez donc stocker toutes ces informations dans la même base de données, c'est ainsi que la plupart des applications le font. La table de base de données qui contient les hachages contient également généralement les sels et toutes les autres informations sur l'algorithme de hachage.
Si vous utilisez une bonne méthode de hachage (utilisez la bibliothèque appropriée, n'essayez pas d'implémenter un algorithme de hachage vous-même!), Personne ne pourra récupérer les mots de passe sans les forcer. Cela ne signifie pas pour autant que ce sera impossible! Les mots de passe faibles resteront des mots de passe faibles, donc 12345
et admin
seront toujours faciles à deviner, bien sûr.
Le HTTPS est important partout, à tout moment, pour tout le monde. Les attaquants ne sont pas seulement là-bas, loin, dans des pays étrangers. Un attaquant peut être votre collègue, un ancien collègue, un visiteur, une personne qui s'introduit par effraction, ou même un routeur infecté ou tout autre appareil. Alors débarrassez-vous de HTTP chaque fois que vous le pouvez. Avec un peu de chance, HTTP disparaîtra un jour.
Les cookies sont acceptables pour la gestion des sessions, mais vous devez faire attention à plusieurs détails. Par exemple, utilisez des cookies HTTP uniquement, assurez-vous que les ID de session contenus dans les cookies sont vraiment aléatoires et impossibles à deviner, décidez si vous devez définir une heure d'expiration (si l'utilisateur sera déconnecté après un certain temps d'inactivité?), etc.
Il s'agit d'un ingénieur logiciel ici. Je répondrai de ce point de vue.
Mon réseau local possède de nombreux appareils exécutant de simples serveurs Web
Vous devriez vraiment essayer de voir si vous pouvez utiliser SSO (Single Sign On).
Avant de dire quelques détails, l'authentification unique est essentiellement ne stocke pas les mots de passe dans votre application. Vous vous reposerez sur un tiers sécurisé, comme Active Directory. Après tout, est-ce un environnement d'entreprise? Cool
Si vous voulez opter pour ce chemin, vous aurez le principal avantage que vous n'avez pas à gérer ou réinventer la sécurité. La gestion des mots de passe n'est pas chose facile et devoir écrire du code pour un système d'authentification plutôt que intégration avec un framework open source existant est une odeur de conception.
L'utilisation d'un tiers comme source d'authentification vous soulage de ce problème et évite aux utilisateurs d'avoir trop de mots de passe. Encore une fois, il existe des bibliothèques pour divers SSO tout autour le monde Github, vous n'aurez donc pas à réécrire à partir de zéro.
Pensez que si vous stockez le mot de passe sur le serveur de chaque appareil, il y aura une copie (du hachage) du mot de passe pour chaque serveur, et ils ne seront pas synchronisés si l'utilisateur décide de le changer ou lorsqu'ils sont réinitialisés. Si vous avez 5 appareils ... ou 1000 appareils ... dites-moi l'expérience!
L'authentification unique basée sur AD la plus simple signifie que l'utilisateur tape le mot de passe sur l'écran de connexion mais que ce mot de passe n'est jamais stocké dans le portail, il est envoyé au contrôleur de domaine central pour validation. Je ne discuterai pas de la gestion des autorisations.
Active Directory n'est qu'un exemple. Il existe d'autres outils.
Quant aux autres points
Tout utilise actuellement http. Https est-il nécessaire si tous les accès se trouvent sur le réseau local?
Partout où un utilisateur tape un mot de passe, https est obligatoire. Il y a plusieurs excellentes raisons à cela:
Même dans les petits bureaux, il peut y avoir un mauvais joueur essayant d'exécuter Wireshark sur le LAN et de renifler un mot de passe, peut-être le mot de passe de leur manager. Pour faire quoi? Ça dépend ... Accéder à la paie ?????
L'utilisation d'un cookie est-elle un bon moyen de vérifier qu'un utilisateur s'est correctement connecté?
Le cookie est utilisé pour la fonction "se souvenir de moi" après que l'utilisateur s'est authentifié. Ils n'auront donc pas à retaper le mot de passe. Pour la portée de cette réponse, je dirais que oui, c'est une bonne façon. Mais vous DEVEZ utiliser https et protéger votre application contre les attaques XSRF. Je n'en discuterai pas ici. Les cookies sont utilisés par Google et Facebook de la bonne manière. S'ils utilisent des cookies, pourquoi pas vous?
Avertissement: je ne reçois pas d'argent mon Microsoft. J'écris juste l'exemple le plus simple qui me vient à l'esprit
Je ne sais pas où vous avez l'intention de placer cet écran de connexion, mais je suppose que vous allez réécrire une partie des serveurs pour ajouter une page de connexion. Je ne comprends pas vraiment ce qu'est "le serveur" écrit en Python dont vous parlez.
Quoi qu'il en soit, ne réinventez pas comment stocker les mots de passe. Il existe des méthodes pour cela et puisque vous mentionnez Python, un bon point de départ peut être le documentation Django à ce sujet .
Cela permettra également de savoir comment conserver la session (via un cookie par exemple)
Pour un aperçu général du stockage des mots de passe, voir ceci réponse 201 par Thomas Pornin. Vous pouvez envisager d'utiliser Argon2 comme algorithme de hachage.
Enfin, vous voudrez peut-être lire OWASP positionnement sur cette question, qui mentionne que (c'est moi qui souligne)
Comme avec la plupart des domaines de la cryptographie, il existe de nombreux facteurs différents qui doivent être pris en compte, mais heureusement, la majorité des langages et des cadres modernes fournissent des fonctionnalités intégrées pour aider à stocker les mots de passe, qui gère une grande partie de la complexité .