(engendré à partir de ce fil car c'est vraiment une question en soi et non spécifique à NodeJS, etc.)
J'implémente un serveur API REST avec authentification et j'ai implémenté avec succès la gestion des jetons JWT afin qu'un utilisateur puisse se connecter via un point de terminaison / login avec un nom d'utilisateur / mot de passe, sur lequel un jeton JWT est généré à partir d'un secret de serveur et renvoyé au client. Le jeton est ensuite passé du client au serveur dans chaque demande d'API authentifiée, sur laquelle le secret du serveur est utilisé pour vérifier le jeton.
Cependant, j'essaie de comprendre les meilleures pratiques pour savoir exactement comment et dans quelle mesure le jeton doit être validé, pour créer un système vraiment sécurisé. Que faut-il impliquer exactement dans la «validation» du jeton? Est-il suffisant que la signature puisse être vérifiée à l'aide du secret du serveur, ou dois-je également contre-vérifier le jeton et / ou la charge utile du jeton par rapport à certaines données stockées sur le serveur?
Un système d'authentification basé sur des jetons ne sera aussi sûr que de transmettre un nom d'utilisateur / mot de passe dans chaque demande à condition qu'il soit tout aussi ou plus difficile d'obtenir un jeton que d'obtenir le mot de passe d'un utilisateur. Cependant, dans les exemples que j'ai vus, les seules informations requises pour produire un jeton sont le nom d'utilisateur et le secret côté serveur. Cela ne signifie-t-il pas qu'en supposant pendant une minute qu'un utilisateur malveillant acquiert la connaissance du secret du serveur, il peut maintenant produire des jetons au nom de n'importe quel utilisateur, ayant ainsi accès non seulement à un utilisateur donné, comme le serait le fait si un mot de passe était obtenu, mais en fait à tous les comptes d'utilisateurs?
Cela m'amène aux questions:
1) La validation du jeton JWT devrait-elle être limitée à la vérification de la signature du jeton lui-même, en s'appuyant uniquement sur l'intégrité du secret du serveur, ou accompagnée d'un mécanisme de validation distinct?
Dans certains cas, j'ai vu l'utilisation combinée de jetons et de sessions serveur où, lors d'une connexion réussie via le point de terminaison / login, une session est établie. Les demandes d'API valident le jeton et comparent également les données décodées trouvées dans le jeton avec certaines données stockées dans la session. Cependant, utiliser des sessions signifie utiliser des cookies et, dans un certain sens, cela va à l'encontre de l'objectif d'utiliser une approche basée sur des jetons. Cela peut également causer des problèmes à certains clients.
On pourrait imaginer que le serveur garde tous les jetons actuellement utilisés dans un cache mémoire ou similaire, pour s'assurer que même si le secret du serveur est compromis de sorte qu'un attaquant puisse produire des jetons «valides», seuls les jetons exacts qui ont été générés via le point de terminaison / login serait accepté. Est-ce raisonnable ou simplement redondant / exagéré?
2) Si la vérification de la signature JWT est le seul moyen de valider les jetons, ce qui signifie que l'intégrité du secret du serveur est le point de rupture, comment les secrets du serveur doivent-ils être gérés? Lire à partir d'une variable d'environnement et créé (aléatoire?) Une fois par pile déployée? Renouvelé ou pivoté périodiquement (et si tel est le cas, comment gérer les jetons valides existants qui ont été créés avant la rotation mais qui doivent être validés après la rotation, peut-être suffit-il si le serveur conserve le secret actuel et le secret précédent à un moment donné) ? Autre chose?
Peut-être que je suis simplement trop paranoïaque en ce qui concerne le risque de compromission du secret du serveur, ce qui est bien sûr un problème plus général qui doit être résolu dans toutes les situations cryptographiques ...
RSAPrivateKey privateKey
??Réponses:
J'ai également joué avec des jetons pour mon application. Bien que je ne sois en aucun cas un expert, je peux partager certaines de mes expériences et réflexions sur la question.
Le but des JWT est essentiellement l'intégrité. Il fournit un mécanisme permettant à votre serveur de vérifier que le jeton qui lui a été fourni est authentique et a été fourni par votre serveur. La signature générée via votre secret est ce qui prévoit cela. Donc, oui, si votre secret est divulgué d'une manière ou d'une autre, cet individu peut générer des jetons que votre serveur penserait être les siens. Un système basé sur des jetons serait toujours plus sécurisé que votre système de nom d'utilisateur / mot de passe simplement en raison de la vérification de la signature. Et dans ce cas, si quelqu'un a de toute façon votre secret, votre système a d'autres problèmes de sécurité à résoudre que quelqu'un qui fabrique de faux jetons (et même dans ce cas, le simple fait de changer le secret garantit que tous les jetons créés avec l'ancien secret sont désormais invalides).
En ce qui concerne la charge utile, la signature vous indiquera seulement que le jeton qui vous a été fourni était exactement tel qu'il était lorsque votre serveur l'a envoyé. vérifier que le contenu des charges utiles est valide ou approprié pour votre application est évidemment à vous.
Pour vos questions:
1.) D'après mon expérience limitée, il est certainement préférable de vérifier vos jetons avec un deuxième système. Valider simplement la signature signifie simplement que le jeton a été généré avec votre secret. Le stockage des jetons créés dans une sorte de base de données (redis, memcache / sql / mongo ou un autre stockage) est un moyen fantastique de vous assurer que vous n'acceptez que les jetons créés par votre serveur. Dans ce scénario, même si votre secret est divulgué, cela n'aura pas trop d'importance car les jetons générés ne seront pas valides de toute façon. C'est l'approche que j'adopte avec mon système - tous les jetons générés sont stockés dans une base de données (redis) et à chaque demande, je vérifie que le jeton est dans ma base de données avant de l'accepter. De cette façon, les jetons peuvent être révoqués pour n'importe quelle raison, comme les jetons qui ont été libérés dans la nature, la déconnexion de l'utilisateur, les changements de mot de passe, les changements de secret, etc.
2.) C'est quelque chose dans lequel je n'ai pas beaucoup d'expérience et c'est quelque chose que je recherche toujours activement car je ne suis pas un professionnel de la sécurité. Si vous trouvez des ressources, n'hésitez pas à les publier ici! Actuellement, j'utilise simplement une clé privée que je charge à partir du disque, mais c'est évidemment loin d'être la solution la meilleure ou la plus sécurisée.
la source
Voici quelques éléments à prendre en compte lors de la mise en œuvre de JWT dans votre application:
Gardez votre durée de vie JWT relativement courte et faites-en gérer la durée de vie sur le serveur. Si vous ne le faites pas et que vous avez besoin ultérieurement de plus d'informations dans vos JWT, vous devrez soit prendre en charge 2 versions, soit attendre que vos anciens JWT aient expiré avant de pouvoir implémenter votre modification. Vous pouvez facilement le gérer sur le serveur si vous ne regardez que le
iat
champ dans le jwt et ignorez leexp
champ.Pensez à inclure l'url de la requête dans votre JWT. Par exemple, si vous souhaitez que votre JWT soit utilisé au point de terminaison
/my/test/path
, incluez un champ comme'url':'/my/test/path'
dans votre JWT, pour vous assurer qu'il n'est jamais utilisé que sur ce chemin. Si vous ne le faites pas, vous constaterez peut-être que les utilisateurs commencent à utiliser vos JWT à d'autres points de terminaison, même ceux pour lesquels ils n'ont pas été créés. Vous pouvez également envisager d'inclure un md5 (url) à la place, car avoir une grande URL dans le JWT finira par rendre le JWT beaucoup plus grand, et ils peuvent devenir assez gros.L'expiration de JWT doit être configurable par chaque cas d'utilisation si les JWT sont mis en œuvre dans une API. Par exemple, si vous avez 10 points de terminaison pour 10 cas d'utilisation différents pour les JWT, assurez-vous que vous pouvez faire en sorte que chaque point de terminaison accepte les JWT qui expirent à des moments différents. Cela vous permet de verrouiller certains points de terminaison plus que d'autres, si, par exemple, les données servies par un point de terminaison sont très sensibles.
Au lieu d'expirer simplement les JWT après un certain temps, envisagez d'implémenter des JWT qui prennent en charge les deux:
Tous les échecs d'authentification JWT doivent générer un en-tête de réponse "erreur" indiquant pourquoi l'authentification JWT a échoué. par exemple "expiré", "aucune utilisation laissée", "révoqué", etc. Cela aide les implémenteurs à savoir pourquoi leur JWT échoue.
Pensez à ignorer l '«en-tête» de vos JWT car ils fuient des informations et donnent une mesure de contrôle aux pirates. Ceci concerne principalement le
alg
champ dans l'en-tête - ignorez cela et supposez simplement que l'en-tête est ce que vous voulez prendre en charge, car cela évite aux pirates d'essayer d'utiliser l'None
algorithme, ce qui supprime le contrôle de sécurité de la signature.Les JWT doivent inclure un identifiant détaillant quelle application a généré le jeton. Par exemple, si vos JWT sont créés par 2 clients différents, mychat et myclassifiedsapp, chacun doit inclure son nom de projet ou quelque chose de similaire dans le champ "iss" du JWT, par exemple "iss": "mychat"
iat
(émis à) au lieu deexp
(expiration) dans vos JWT. Pourquoi? Puisque celaiat
signifie essentiellement quand le JWT a été créé, cela vous permet d'ajuster sur le serveur quand le JWT expire, en fonction de la date de création. Si quelqu'un décède dansexp
20 ans dans le futur, le JWT vit pour toujours! Notez que vous expirez automatiquement les JWT si leuriat
est dans le futur, mais laissez un peu de marge de manœuvre (par exemple 10 secondes), au cas où l'heure du client serait légèrement désynchronisée avec l'heure du serveur./mysite/userInfo?jwt=XXX
et que cette URL soit mise en cache. Ils se déconnectent et quelques minutes plus tard, un utilisateur régulier se connecte à votre application. Ils obtiendront le contenu mis en cache - avec des informations sur un super utilisateur! Cela a tendance à se produire moins sur le client et plus sur le serveur, en particulier dans les cas où vous utilisez un CDN comme Akamai et que vous laissez certains fichiers vivre plus longtemps. Cela peut être résolu en incluant les informations utilisateur pertinentes dans l'URL et en la validant sur le serveur, même pour les demandes en cache, par exemple/mysite/userInfo?id=52&jwt=XXX
la source
created_by
, il y a déjà une réclamation pour cela dans JWT et il est appeléiss
(émetteur).Je ne pense pas être un expert mais j'aimerais partager quelques réflexions sur Jwt.
1: Comme l'a dit Akshay, il est préférable d'avoir un deuxième système pour valider votre jeton.
a: La façon dont je le gère: je stocke le hachage généré dans un stockage de session avec l'heure d'expiration. Pour valider un jeton, il doit avoir été émis par le serveur.
b.:Il y a au moins une chose qui doit être vérifiée la méthode de signature utilisée. par exemple :
Certaines bibliothèques validant JWT accepteraient celui-ci sans vérifier le hachage. Cela signifie que sans connaître votre sel utilisé pour signer le jeton, un pirate informatique pourrait s'octroyer certains droits. Assurez-vous toujours que cela ne peut pas arriver. https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/
c: L'utilisation d'un cookie avec un identifiant de session ne serait pas utile pour valider votre token. Si quelqu'un veut détourner la session d'un utilisateur lambda, il lui suffit d'utiliser un sniffer (par exemple: wirehark). Ce hacker aurait les deux informations en même temps.
La façon dont je le gère est liée au point 1.a. : J'ai un secret mélangé avec une variable aléatoire. Le secret est unique pour chaque jeton.
Si vous voulez la meilleure sécurité possible, vous ne devez pas suivre aveuglément les meilleures pratiques. Le meilleur moyen est de comprendre ce que vous faites (je pense que c'est correct quand je vois votre question), puis d'évaluer la sécurité dont vous avez besoin. Et si le Mossad veut avoir accès à vos données confidentielles, il trouvera toujours un moyen. (J'aime ce billet de blog: https://www.schneier.com/blog/archives/2015/08/mickens_on_secu.html )
la source
Beaucoup de bonnes réponses ici. Je vais intégrer certaines des réponses qui me semblent les plus pertinentes et ajouter d'autres suggestions.
1) La validation du jeton JWT devrait-elle être limitée à la vérification de la signature du jeton lui-même, en s'appuyant uniquement sur l'intégrité du secret du serveur, ou accompagnée d'un mécanisme de validation distinct?
Non, pour des raisons indépendantes de la compromission d'un jeton secret. Chaque fois qu'un utilisateur se connecte via un nom d'utilisateur et un mot de passe, le serveur d'autorisation doit stocker soit le jeton qui a été généré, soit des métadonnées sur le jeton qui a été généré. Considérez ces métadonnées comme un enregistrement d'autorisation. Une paire utilisateur et application donnée ne doit avoir qu'un seul jeton valide, ou autorisation, à un moment donné. Les métadonnées utiles sont l'ID utilisateur associé au jeton d'accès, l'ID d'application et l'heure à laquelle le jeton d'accès a été émis (ce qui permet la révocation des jetons d'accès existants et l'émission d'un nouveau jeton d'accès). À chaque demande d'API, vérifiez que le jeton contient les métadonnées appropriées. Vous devez conserver les informations sur la date d'émission de chaque jeton d'accès, afin qu'un utilisateur puisse révoquer les jetons d'accès existants si les informations d'identification de son compte sont compromises, se reconnecter et commencer à utiliser un nouveau jeton d'accès. Cela mettra à jour la base de données avec l'heure à laquelle le jeton d'accès a été émis (l'heure d'autorisation créée). Sur chaque demande d'API, vérifiez que l'heure d'émission du jeton d'accès est postérieure à l'heure d'autorisation créée.
D'autres mesures de sécurité comprenaient la non-journalisation des JWT et la nécessité d'un algorithme de signature sécurisé tel que SHA256.
2) Si la vérification de la signature JWT est le seul moyen de valider les jetons, ce qui signifie que l'intégrité du secret du serveur est le point de rupture, comment les secrets du serveur doivent-ils être gérés?
La compromission des secrets du serveur permettrait à un attaquant d'émettre des jetons d'accès pour n'importe quel utilisateur, et le stockage des données des jetons d'accès à l'étape 1 n'empêcherait pas nécessairement le serveur d'accepter ces jetons d'accès. Par exemple, supposons qu'un utilisateur a reçu un jeton d'accès, puis plus tard, un attaquant génère un jeton d'accès pour cet utilisateur. L'heure d'autorisation du jeton d'accès serait valide.
Comme le dit Akshay Dhalwala, si votre secret côté serveur est compromis, vous avez de plus gros problèmes à résoudre car cela signifie qu'un attaquant a compromis votre réseau interne, votre référentiel de code source ou les deux.
Cependant, un système pour atténuer les dommages d'un secret de serveur compromis et éviter de stocker des secrets dans le code source implique une rotation de jeton de secret à l'aide d'un service de coordination comme https://zookeeper.apache.org. Utilisez une tâche cron pour générer un secret d'application toutes les quelques heures environ (quelle que soit la durée de validité de vos jetons d'accès) et transmettez le secret mis à jour à Zookeeper. Dans chaque serveur d'applications qui a besoin de connaître le secret du jeton, configurez un client ZK qui est mis à jour chaque fois que la valeur du nœud ZK change. Stockez un secret principal et un secret secondaire, et chaque fois que le secret de jeton est modifié, définissez le nouveau secret de jeton sur le secret principal et l'ancien secret de jeton sur le secondaire. De cette façon, les jetons valides existants seront toujours valides car ils seront validés par rapport au secret secondaire. Au moment où le secret secondaire est remplacé par l'ancien secret principal, tous les jetons d'accès émis avec le secret secondaire expireront de toute façon.
la source
L'IETF a une RFC en cours dans le groupe de travail oAuth voir: https://tools.ietf.org/id/draft-ietf-oauth-jwt-bcp-05.html
la source