92 votes

Authentification REST et exposition de la clé API

J'ai lu sur le RESTE et il y a beaucoup de questions DONC, à ce sujet, comme sur beaucoup d'autres sites et blogs. Bien que je n'ai jamais vu cette question posée...pour une raison quelconque, je ne peux pas envelopper mon esprit autour de ce concept...

Si je suis en train de construire une API RESTful, et je veux la protéger, l'une des méthodes que j'ai vu est l'utilisation d'un jeton de sécurité. Lorsque j'ai utilisé d'autres Api, il y a eu un jeton et un secret partagé...de sens. Ce que je ne comprends pas, c'est, à la demande d'un temps de fonctionnement du service sont réalisés à l'aide de javascript (XHR/Ajax), ce qui est à l'empêcher de renifler qu'avec quelque chose de simple comme FireBug (ou "afficher la source" dans le navigateur) et de la copie de la clé API, puis en empruntant l'identité de cette personne à l'aide de la clé et le secret?

60voto

Arjan Points 7154

Nous allons exposer une API que les partenaires peuvent utiliser uniquement sur les domaines qu'ils ont enregistré avec nous. Son contenu est en partie publique (mais de préférence seulement être indiqué sur les domaines que nous connaissons), mais est le plus souvent privée de nos utilisateurs. Donc:

  • Pour déterminer ce qui est montré, notre utilisateur doit être connecté avec nous, mais c'est géré séparément.

  • Pour déterminer les données sont affichées, une API publique clé est utilisée pour limiter l'accès à des domaines que nous connaissons, et surtout pour assurer le privé, les données de l'utilisateur n'est pas vulnérable à CSRF.

Cette clé API est en effet visible à tout le monde, nous n'avons pas d'authentifier notre partenaire de toute autre manière, et nous n'avez pas besoin de REFERER. Pourtant, c'est sûr:

  1. Lors de notre - get-csrf-token.js?apiKey=abc123 est demandé:

    1. Chercher la clé abc123 dans la base de données et d'obtenir une liste de validité domaines pour cette clé.

    2. Regarder pour la validation CSRF cookie. Si elle n'existe pas, générer une sécurité aléatoire de la valeur et de la mettre dans un HTTP seule cookie de session. Si le cookie n'existe pas, obtenir existants valeur aléatoire.

    3. Créer un jeton CSRF de la clé API et la valeur aléatoire à partir du cookie, et de le signer. (Plutôt que de garder une liste de jetons sur le serveur, nous sommes à la signature de l'valeurs. Les deux valeurs seront lisibles dans le jeton signé, c'est bien.)

    4. Définir le temps de réponse pour ne pas être mis en cache, ajouter le cookie, et de renvoyer un script tel que:

      var apiConfig = apiConfig || {};
      if(document.domain === 'expected-domain.com' 
            || document.domain === 'www.expected-domain.com') {
      
          apiConfig.csrfToken = 'signed token with API key and random number';
      
          // Invoke a callback if the partner wants us to
          if(typeof apiConfig.fnInit !== 'undefined') {
              apiConfig.fnInit();
          }
      } else {
          alert('This site is not authorised for this API key.');
      }
      

    Notes:

    • Le ci-dessus n'empêche pas un serveur de script côté de simuler une demande, mais seulement de sorte que le domaine des matchs si demandé par un navigateur.

    • La même la politique de l'origine pour JavaScript assure qu'un navigateur ne peut pas utiliser XHR (Ajax) pour charger et puis inspectez la source JavaScript. Au lieu de cela, un navigateur ne peut le charger à l'aide de <script src="https://our-api.com/get-csrf-token.js?apiKey=abc123"> (ou une dynamique équivalente), puis exécutez le code. Bien sûr, votre serveur devrait pas soutenir Cross-Origin Resource sharing ni JSONP pour le JavaScript généré.

    • Un script de navigateur peut changer la valeur de document.domain avant le chargement du script ci-dessus. Mais de la même origine que la politique ne permet de raccourcir le domaine par la suppression des préfixes, comme la réécriture subdomain.example.com juste example.comou myblog.wordpress.com de wordpress.com, ou dans certains navigateurs, même bbc.co.uk de co.uk.

    • Si le fichier JavaScript est récupérée à l'aide de certains de script côté serveur, le serveur sera également obtenir le cookie. Toutefois, le serveur d'un tiers ne peut pas faire un navigateur de l'utilisateur associé cookie à notre domaine. Par conséquent, un jeton CSRF et de la validation des cookies qui ont été extraites à l'aide d'un serveur de script côté, ne peut être utilisé par la suite le côté de serveur d'appels, pas dans un navigateur. Toutefois, de telles côté serveur, les appels ne comprennent jamais de l'utilisateur cookie, et donc ne peut récupérer des données publiques. C'est les mêmes données d'un serveur de script côté pourrait gratter à partir du site du partenaire directement.

  2. Lorsqu'un utilisateur se connecte, le jeu de certains cookie utilisateur de n'importe quelle manière que vous aimez. (L'utilisateur pourrait avoir déjà connecté avant le JavaScript a été demandée.)

  3. Toutes les requêtes à l'API du serveur (y compris les OBTENIR et JSONP les demandes doivent inclure le jeton CSRF, la validation CSRF cookie, et (si connecté) l'utilisateur cookie. Le serveur peut maintenant déterminer si la demande est approuvée:

    1. La présence d'un valide jeton CSRF assure le JavaScript a été chargé de la domaine, si chargé dans un navigateur.

    2. La présence du jeton CSRF sans la validation de cookie indique la contrefaçon.

    3. La présence à la fois le jeton CSRF et la validation CSRF cookie ne permet pas d'assurer quoi que ce soit: ce pourrait être soit un faux serveur côté demande, ou d'une demande valide à partir d'un navigateur. (Il ne pouvait pas être une demande à partir d'un navigateur fabriqué à partir d'un domaine non pris en charge.)

    4. La présence du cookie utilisateur garantit à l'utilisateur est connecté, mais ne garantit pas que l'utilisateur est un membre de la partenaire, ni que l'utilisateur consulte le site web correct.

    5. La présence de l'utilisateur cookie sans la validation CSRF cookie indique la contrefaçon.

    6. La présence de l'utilisateur cookie fait en sorte que la demande actuelle est faite par le biais d'un navigateur. (En supposant que l'utilisateur ne serait pas entrer leurs informations d'identification sur un site inconnu, et en supposant que nous ne nous soucions pas les utilisateurs à l'aide de leurs propres informations d'identification pour faire un serveur côté de la demande). Si nous aussi ont la validation CSRF cookie, alors que la validation CSRF cookie a été également reçu l'aide d'un navigateur. Ensuite, si nous avons également avoir un jeton CSRF avec une signature valide, et le nombre aléatoire dans la validation CSRF cookie correspond à celui que le jeton CSRF, puis le JavaScript pour que le jeton a également été reçu au cours de cette même demande antérieure au cours de laquelle le CSRF cookie a été définie, et donc également à l'aide d'un navigateur. Ensuite, cela implique également le code JavaScript ci-dessus a été exécuté avant que le jeton a été définie, et qu'à cette époque, le domaine a été valable pour la clé API.

      Donc: le serveur peut maintenant l'utiliser en toute sécurité la clé API à partir de la signature de jeton.

    7. À tout moment, si le serveur ne fait pas confiance à la demande, puis un 403 Forbidden est retourné. Le widget peut répondre que par l'apparition d'un avertissement à l'utilisateur.

Il n'est pas tenu de signer la validation CSRF cookie, que nous sommes en la comparant à la signature de jeton CSRF. Pas de signer le cookie permet de chaque requête HTTP, plus courte, et le serveur de validation un peu plus vite.

L'généré jeton CSRF est valide indéfiniment, mais seulement en combinaison avec la validation de cookie, donc effectivement, jusqu'à la fermeture du navigateur.

On pourrait limiter la durée de vie du jeton de signature. On pourrait supprimer la validation CSRF cookies lorsque l'utilisateur se déconnecte, pour répondre à l'OWASP recommandation. Et de ne pas partager les par utilisateur nombre aléatoire entre plusieurs partenaires, on pourrait ajouter la clé API pour le nom de cookie. Mais même alors, on ne peut pas facilement actualiser la validation CSRF cookie lorsqu'un nouveau jeton est demandé, les internautes naviguant sur le même site en plusieurs fenêtres, à l'aide d'un seul cookie.

Pour ceux qui utilisent le protocole OAuth, voir aussi OAuth et Côté Client Widgets, à partir de laquelle j'ai obtenu le JavaScript idée. Pour le côté serveur de l'utilisation de l'API, dans lequel on ne peut s'appuyer sur le code JavaScript pour limiter le domaine, nous sommes à l'aide de clés secrètes au lieu de l'API publique clés.

22voto

James.Xu Points 3320

api secret n'est pas explicitement passé, secret est utilisé pour générer un signe de la requête en cours. Du côté serveur, le serveur génère le signe en suivant le même processus. Si les deux signatures correspondent, la requête est authentifiée avec succès. le signe est transmis à travers la demande, pas le secret.

9voto

Chris Points 883

Cette question a accepté de répondre mais juste pour clarifier, le secret partagé l'authentification fonctionne comme ceci:

  1. Le Client dispose de la clé publique, ce qui peut être partagé avec quiconque, n'est-ce pas de la matière, de sorte que vous pouvez l'intégrer dans le code javascript. Ce est utilisé pour identifier l'utilisateur sur le serveur.
  2. Serveur a la clé secrète, et ce secret DOIT être protégé. Par conséquent, l'authentification à clé partagée nécessite que vous pouvez protéger votre secret clé. Ainsi, un public javascript client qui se connecte directement à un autre il n'est pas possible parce que vous avez besoin d'un serveur intermédiaire d' protéger le secret.
  3. Serveur signes demander l'aide d'un algorithme qui comprend le secret clé (la clé secrète est comme une sorte de sel) et de préférence un timestamp envoie ensuite la demande pour le service. L'horodatage est pour éviter les "replay" des attaques. Une signature d'une demande n'est valable que pour autour de n secondes. Vous pouvez le vérifier sur le serveur par l'obtention de l'horodatage en-tête doit contenir la valeur du timestamp qui a été inclus dans la signature. Si ce timestamp est expiré, la demande échoue.
  4. Le service reçoit la demande qui ne contient pas seulement la signature mais aussi de tous les champs qui ont été signés en texte brut.
  5. Ce service, puis signe la demande de la même manière à l'aide de la partagé clé secrète et compare les signatures.

1voto

PeterMmm Points 11099

Je suppose que vous voulez parler de la clé de session et non de la clé API. Ce problème est hérité du protocole http et est appelé piratage de session . La "solution de contournement" normale consiste, comme sur tout site Web, à passer à https.

Pour exécuter le service REST sécurisé, vous devez activer https et probablement l'authentification du client. Mais après tout, cela dépasse l’idée du REST. REST ne parle jamais de sécurité.

1voto

Iain Porter Points 81

Ce que vous voulez faire sur le côté serveur est de générer une expirant identifiant de session qui est envoyé au client lors de la connexion ou inscription. Le client peut alors utiliser cet id de session comme un secret partagé à signer les demandes ultérieures.

L'id de session est transmis uniquement une fois et cela DOIT être sur SSL.

Voir l'exemple ici

L'utilisation d'un nonce et d'horodatage lors de la signature de la demande afin de prévenir le détournement de session.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X