Meilleures pratiques pour la gestion des jetons JWT côté serveur

(générés à partir de ce fil car c'est vraiment une question de son propre et n'est pas spécifique de NodeJS etc)

j'implémente un serveur D'API REST avec authentification, et j'ai implémenté avec succès la gestion des tokens JWT pour qu'un utilisateur puisse se connecter via un terminal /login avec nom d'utilisateur/mot de passe, sur lequel un token JWT est généré à partir d'un secret serveur et retourné au client. Le token est ensuite passé du client au serveur dans chaque requête API authentifiée, sur laquelle le secret du serveur est utilisé pour vérifier le token.

cependant, j'essaie de comprendre les meilleures pratiques pour savoir exactement comment et dans quelle mesure le jeton devrait être validé, pour faire un système vraiment sûr. Que faut-il exactement pour "valider" le jeton? Est-il suffisant que la signature puisse être vérifiée en utilisant le serveur-secret, ou devrais-je également croiser le token et/ou la charge utile du token avec certaines données stockées dans le le serveur?

un système d'authentification basé sur un jeton ne sera aussi sûr que de passer un nom d'utilisateur/mot de passe dans chaque requête, à condition qu'il soit 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, la seule information requise pour produire un token est 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 gagne la connaissance du secret du serveur, il peut maintenant produire des jetons sur au nom de tout utilisateur, ayant ainsi accès non seulement à un utilisateur donné comme ce serait le cas si un mot de passe était obtenu, mais en fait à tous comptes d'utilisateur?

cela m'amène aux questions:

1) la validation du JWT token devrait-elle se limiter à vérifier la signature du jeton lui-même, en se fondant uniquement sur l'intégrité du serveur secret, ou devrait-elle être accompagnée d'un mécanisme de validation distinct?

  • dans certains cas, j'ai vu l'utilisation combinée de tokens et de sessions de serveur où, après une connexion réussie via le point final /login, une session est établie. Les requêtes API valident le token, et comparent également les données décodées trouvées dans le token 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 les tokens. Il peut également causer des problèmes pour certains clients.

  • on pourrait imaginer que le serveur garde tous les tokens actuellement utilisés dans une memcache ou similaire, pour s'assurer que même si le secret du serveur est compromis afin qu'un attaquant puisse produire des tokens "valides", seuls les tokens exacts qui ont été générés par le point final /login seraient acceptés. Est-ce raisonnable ou juste redondant/exagéré?

2) Si JWT de vérification de la signature est le seul moyen de valider jetons, ce qui signifie 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éé (randomisés? plus d'une fois par déployés pile? Si oui, 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 est-ce suffisant si le serveur conserve le secret actuel et le secret précédent à un moment donné? Quelque chose d'autre?

Peut-être que je suis simplement trop paranoïaque quand il s'agit du risque que le secret du serveur soit compromis, ce qui est bien sûr un problème plus général qui doit être abordé dans toutes les situations cryptographiques...

83
demandé sur Community 2015-05-29 10:06:18

4 réponses

j'ai aussi joué avec des jetons pour mon application. Bien que je ne sois pas un expert, je peux partager certaines de mes expériences et réflexions sur la question.

le point de JWTs est essentiellement l'intégrité. Il fournit un mécanisme pour votre serveur vérifier que le token qui lui a été fourni est authentique et a été fourni par votre serveur. La signature générée par votre secret est ce qui permet cela. Donc, oui, si votre secret est divulgué d'une façon ou d'une autre, individual peut générer des tokens que votre serveur penserait être les siens. Un système basé sur un jeton serait encore plus sûr que votre système de nom d'utilisateur/mot de passe simplement à cause de la vérification de la signature. Et dans ce cas, si quelqu'un a votre secret de toute façon, votre système a d'autres problèmes de sécurité à traiter que quelqu'un faisant de faux jetons (et même alors, juste changer le secret assure que tous les jetons faits avec le vieux secret sont maintenant invalides).

en ce qui concerne la charge utile, le signature vous dirai seulement que le jeton fourni était exactement comme il était lors de votre serveur l'a envoyé. vérifier que les charges contenu est valide ou approprié pour votre application est évidemment à vous.

pour vos questions:

1.), Dans mon expérience limitée, il est certainement préférable de vérifier vos jetons avec un deuxième système. Valider la signature signifie simplement que le jeton a été généré avec votre secret. Le stockage de tout créer des tokens dans une sorte de DB (redis, memcache/sql/mongo, ou un autre stockage) est une façon fantastique de s'assurer que vous n'acceptez que les tokens que votre serveur a créés. Dans ce scénario, même si votre secret est divulgué, cela n'aura pas trop d'importance car tout Token généré ne sera pas valide de toute façon. C'est l'approche que j'adopte avec mon système - tous les tokens générés sont stockés dans un DB (redis) et sur chaque requête, je vérifie que le token est dans mon DB avant de l'accepter. De cette façon, les jetons peuvent être révoqué pour n'importe quelle raison, comme les tokens qui ont été libérés dans le wild d'une manière ou d'une autre, la déconnexion de l'utilisateur, les changements de mot de passe, les changements secrets, etc.

2. C'est quelque chose que je n'ai pas beaucoup d'expérience et que je recherche encore activement, car je ne suis pas un professionnel de la sécurité. Si vous trouvez des ressources, n'hésitez pas à les poster ici! Actuellement, j'utilise juste une clé privée que je charge à partir du disque, mais de toute évidence, c'est loin d'être la meilleure ou la solution la plus sûre.

44
répondu Akshay Dhalwala 2015-06-17 22:17:46

voici quelques éléments à considérer lors de la mise en œuvre de JWT dans votre application:

  • Gardez votre durée de vie JWT relativement courte, et faites-la gérer par le serveur. Si vous ne le faites pas, et que vous avez besoin plus tard de plus d'informations dans vos JWTs, vous devrez soit prendre en charge 2 versions, soit attendre que vos JWTS plus anciens soient expirés avant de pouvoir mettre en œuvre votre changement. Vous pouvez facilement gérer sur le serveur si vous regardez seulement le iat dans le champ jwt, et ignorer le champ exp .

  • envisagez d'inclure l'url de la demande dans votre JWT. Par exemple , si vous voulez que votre JWT soit utilisé au point final /my/test/path , incluez un champ comme 'url':'/my/test/path' dans votre JWT, pour vous assurer qu'il n'est jamais utilisé à ce chemin. Si vous ne le faites pas, vous constaterez peut-être que les gens commencent à utiliser vos JWT à d'autres fins, même celles pour lesquelles ils n'ont pas été créés. Vous pourriez aussi envisager d'inclure un md5 (url) au lieu de cela, comme ayant une grande url dans le JWT finira par faire le JWT que beaucoup plus grand, et ils peuvent obtenir assez grand.

  • l'expiration JWT doit être configurable par chaque cas d'utilisation si les JWTs sont implémentés dans une API. Par exemple, si vous avez 10 paramètres pour 10 cas d'utilisation différents pour les JWT, assurez-vous que vous pouvez faire en sorte que chaque paramètre accepte les JWT qui expirent à des moments différents. Cela vous permet de verrouiller certains paramètres plus que d'autres, si pour par exemple, les données servies par un paramètre sont très sensibles.

  • au lieu de simplement expirer JWTs après un certain temps, envisager de mettre en œuvre JWTs qui soutiennent les deux:

    • n usages - ne peut être utilisé que N fois avant leur expiration et
    • expire après un certain temps (si vous avez un jeton d'usage unique, vous ne voulez pas qu'il vive éternellement s'il n'est pas utilisé, n'est-ce pas?)
  • toutes les erreurs D'authentification JWT doivent générer un en-tête de réponse "error" qui indique pourquoi L'authentification JWT a échoué. par exemple, "expiré", "non aux usages de gauche", "révoqué", etc. Cela permet aux exécutants de savoir pourquoi leur JWT échoue.

  • envisagez de ne pas tenir compte de l '"en-tête" de vos JWTs, car ils font fuiter des informations et donnent une mesure de contrôle aux pirates. Il s'agit principalement du alg champ dans l'en-tête-ignorez ceci et supposez simplement que l'en-tête est ce que vous voulez supporter, car cela évite aux pirates d'essayer d'utiliser l'algorithme None , qui supprime la vérification de sécurité de signature.

  • JWT devraient inclure un identifiant détaillant l'application qui a généré le jeton. Par exemple, si vos JWT sont créés par 2 clients différents, mychat, et myclassifiedsapp, alors chacun devrait inclure son nom de projet ou quelque chose de similaire. dans le champ "iss" dans la JWT p.ex. "iss": "MyChat "

  • JWT ne doit pas être enregistré dans les fichiers journaux. Le contenu D'une JWT peut être enregistré, mais pas la JWT elle-même. Cela garantit que les devs ou d'autres ne peuvent pas saisir JWT à partir de fichiers journaux et faire des choses à d'autres comptes utilisateurs.
  • assurez-vous que votre implémentation JWT n'autorise pas l'algorithme" None", pour éviter que les hackers créent des tokens sans les signer. Cette classe d'erreurs peut être entièrement évité par ignorant l '"en-tête" de votre JWT.
  • envisagez fortement d'utiliser iat (délivré à) au lieu de exp (expiration) dans votre JWTs. Pourquoi? Puisque iat signifie essentiellement quand le JWT a été créé, cela vous permet de régler sur le serveur quand le JWT expire, basé sur la date de création. Si quelqu'un passe dans un exp qui est de 20 ans dans le futur, le JWT vit essentiellement pour toujours! Notez que vous expirez automatiquement JWTs si leur iat est dans le futur, mais prévoir un peu de marge de manœuvre (p. ex. g 10 secondes), dans le cas où le temps du client est légèrement hors de synchronisation avec le temps des serveurs.
  • envisagez d'implémenter un endpoint pour créer des JWTs à partir d'une charge json, et forcez tous vos clients à utiliser ce endpoint pour créer leurs JWTs. Cela garantit que vous pouvez résoudre tous les problèmes de sécurité que vous voulez avec la façon dont JWTs sont créés dans un endroit, facilement. Nous ne l'avons pas fait directement dans notre application, et nous devons maintenant faites glisser lentement les mises à jour de sécurité Côté Serveur JWT parce que nos 5 clients différents ont besoin de temps pour mettre en œuvre. De plus, faites en sorte que votre terminal create accepte un tableau de charges json que JWTs peut créer, ce qui diminuera le nombre de requêtes http entrant à ce terminal pour vos clients.
  • si vos JWT seront utilisés à des fins qui supportent aussi l'utilisation par session, assurez-vous de ne pas mettre quoi que ce soit dans votre JWT qui est requis pour satisfaire la demande. Vous pouvez facilement le faire si vous assurez-vous que votre endpoint fonctionne avec une session, lorsqu'aucun JWT n'est fourni.
  • donc JWT's généralement parler finissent par contenir un userId ou groupId d'une sorte, et permettre l'accès à une partie de votre système basé sur cette information. Assurez-vous que vous n'autorisez pas les utilisateurs d'un secteur de votre application à usurper l'identité d'autres utilisateurs, surtout si cela permet l'accès à des données sensibles. Pourquoi? Même si votre processus de génération JWT n'est accessible qu'aux services "internes", aux dev ou à d'autres services internes les équipes pourraient générer des JWT pour accéder aux données pour n'importe quel utilisateur, par exemple le PDG de l'entreprise d'un client aléatoire. Par exemple, si votre application fournit l'accès aux dossiers financiers pour les clients, puis en générant une JWT, un dév pourrait saisir les dossiers financiers de n'importe quelle entreprise du tout! Et si hacker pénètre dans votre réseau interne de toute façon, ils pourraient faire la même chose.
  • si vous allez permettre à n'importe quelle url qui contient un JWT d'être mise en cache de n'importe quelle façon, assurez-vous que les permissions pour différents les utilisateurs sont inclus dans l'url, et pas le JWT. Pourquoi? Parce que les utilisateurs peuvent finir par obtenir des données qu'ils ne devraient pas. Par exemple, disons qu'un super utilisateur se connecte à votre application , et demande l'url suivante: /mysite/userInfo?jwt=XXX , et que cette url est mise en cache. Ils déconnexion et quelques minutes plus tard, un utilisateur se connecte à votre application. Ils obtiendront le contenu caché - avec des informations sur un super utilisateur! Cela tend à se produire moins sur le client, et plus sur le serveur, surtout dans les cas où vous utilisez un CDN comme Akamai, et tu laisses certains fichiers vivre plus longtemps. Ceci peut être corrigé en incluant les informations utilisateur pertinentes dans l'url, et en les validant sur le serveur, même pour les requêtes mises en cache, par exemple /mysite/userInfo?id=52&jwt=XXX
21
répondu Brad Parks 2018-01-23 11:12:29

Je ne pense pas être un expert mais j'aimerais partager quelques réflexions sur Jwt.

  • 1: comme Akshay L'a dit, il est préférable d'avoir un second système pour valider votre token.

    A.: La façon dont je le gère : je stocke le hash généré dans un stockage de session avec le temps expiricy. Pour valider un jeton, il doit avoir été émis par le serveur.

    B.:Il y a au moins une chose il faut vérifier la méthode de signature utilisée. par exemple :

    header :
    {
      "alg": "none",
      "typ": "JWT"
    }
    

certaines bibliothèques validant JWT accepteraient celle-ci sans vérifier le hachage. Cela signifie que sans savoir que votre sel avait l'habitude de signer le jeton, un hacker pourrait s'accorder des 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.: Utilisation un cookie avec un Identifiant de session ne serait pas utile pour valider votre jeton. Si quelqu'un veut détourner la session d'un utilisateur lambda, il suffit d'utiliser un sniffer (par exemple : wireshark). Ce pirate informatique aurait deux informations en même temps.

  • 2: C'est la même chose pour tout secret. Il y a toujours un moyen de le savoir.

la façon dont je la gère est liée au point 1.un. : J'ai un secret mélangé avec un variable aléatoire. Le secret est unique pour chaque jeton.

cependant, j'essaie de comprendre les meilleures pratiques pour savoir exactement comment et dans quelle mesure le jeton devrait être validé, pour faire un système sécurisé.

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 ok quand je vois votre question), puis d'évaluer la la sécurité dont vous avez besoin. Et si le Mossad veut avoir accès à vos données confidentielles, ils trouveront toujours un moyen. (J'aime ce billet de blog: https://www.schneier.com/blog/archives/2015/08/mickens_on_secu.html )

8
répondu Deblaton Jean-Philippe 2017-11-24 13:14:44

Beaucoup de bonnes réponses ici. Je vais intégrer certaines des réponses que je pense les plus pertinentes et ajouter quelques suggestions.

1) la validation du JWT token devrait-elle se limiter à vérifier la signature du jeton lui-même, en se fondant uniquement sur l'intégrité du serveur secret, ou devrait-elle être accompagnée d'un mécanisme de validation distinct?

non, pour des raisons sans rapport avec le compromis d'un secret symbolique. Chaque fois qu'un utilisateur se connecte via un nom d'utilisateur et mot de passe, le serveur d'autorisation devrait stocker soit le token qui a été généré, soit des métadonnées sur le token qui a été généré. Considérez ces métadonnées comme un enregistrement d'autorisation. Un utilisateur donné et une paire d'applications ne devraient avoir qu'un seul token valide, ou autorisation, à un moment donné. Les métadonnées utiles est l'id de l'utilisateur associé avec le jeton d'accès, l'id de l'application, et le moment où le jeton d'accès a été publié (ce qui permet la révocation de l'existant, des jetons d'accès et l'émission d'un nouveau jeton d'accès). Pour chaque requête API, validez que le token contient les métadonnées appropriées. Vous devez persister les informations sur la date à laquelle chaque Token d'accès a été émis, afin qu'un utilisateur puisse révoquer les tokens d'accès existants si ses informations de compte sont compromises, et se connecter à nouveau et commencer à utiliser un nouveau token d'accès. Qui 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 requête API, vérifiez que l'heure d'émission du token d'accès est après le temps d'autorisation créé.

D'autres mesures de sécurité incluaient la non-journalisation des JWT et l'exigence d'un algorithme de signature sécurisé comme SHA256.

2) si la vérification de 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 gérer les secrets du serveur?

la compromission des secrets du serveur permettrait à un attaquant de délivrer des jetons d'accès pour tout utilisateur, et stocker les données des tokens d'accès à l'étape 1 n'empêcherait pas nécessairement le serveur d'accepter ces tokens d'accès. Par exemple, supposons qu'un utilisateur a été délivré un jeton d'accès, et puis, plus tard, un attaquant génère un jeton d'accès pour cet utilisateur. L'autorisation moment de le jeton d'accès valable.

comme dit Akshay Dhalwala, si votre secret côté serveur est compromis, alors vous avez de plus gros problèmes à traiter parce que cela signifie qu'un attaquant a compromis votre réseau interne, votre dépôt 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 secret token en utilisant un service de coordination comme https://zookeeper.apache.org . Utilisez une tâche cron pour générer une application secrète toutes les quelques heures environ (quelle que soit la durée de validité de vos tokens d'accès), et poussez le secret mis à jour à Zookeeper. Dans chaque le serveur d'application qui a besoin de connaître le secret du jeton, configure un client ZK qui est mis à jour à chaque fois que la valeur du noeud ZK change. Conservez un secret primaire et un secret secondaire, et chaque fois que le jeton secret est changé, mettez le nouveau jeton secret au primaire et l'ancien jeton secret au secondaire. De cette façon, les jetons valides existants seront toujours valides parce qu'ils seront validés par rapport au secret secondaire. Le temps que le secret secondaire soit remplacé par le vieux secret primaire, tout le les jetons d'accès délivrés avec le secret secondaire seraient de toute façon périmés.

2
répondu skeller88 2017-07-15 07:29:59