Comment un Facebook jeton d'accès utilisateur consommée sur le côté serveur?

préface

je développe plusieurs services web et une poignée de clients (application web, mobile, etc.) qui s'interfacera avec lesdits services via HTTP(s). Mon travail actuel consiste à concevoir une solution d'authentification et d'autorisation pour le produit. J'ai décidé de miser sur des fournisseurs d'identité externes, comme Facebook, Google, Microsoft, Twitter, etc. pour l'authentification.

j'essaie de résoudre le problème de, "quand une requête arrive sur mon serveur, comment puis-je savoir qui est l'utilisateur et comment puis-je en être sûr?". Plus de questions ci-dessous...

exigences

"
  1. S'appuient sur des identités externes pour indiquer à qui j'ai affaire ("userId" est essentiellement tout ce qui m'importe).
  2. le système doit utiliser l'authentification par token (par opposition aux cookies par exemple ou à l'authentification de base).

    je crois que c'est le bon choix pour mettre à l'échelle plusieurs clients et serveurs tout en fournissant le couplage lâche.

Flux de travail

en me basant sur ma lecture et ma compréhension de l'authentification par token, voici comment j'imagine le flux de travail. Concentrons-nous pour l'instant sur Facebook dans un navigateur web . Mon hypothèse est que les autres externes les fournisseurs d'identité devraient avoir des capacités similaires, bien que je ne l'ai pas encore confirmé.

Note, au moment d'écrire, je base la suivante sur la version de connexion Facebook 2.2

  1. Client: initie la connexion à Facebook en utilisant le JavaScript SDK
  2. Facebook: l'utilisateur authentifie et approuve les permissions de l'application (pour accéder au public de l'utilisateur) profil par exemple)
  3. Facebook: envoie la réponse au client qui contient le jeton d'accès de l'utilisateur, L'ID, et la demande signée
  4. Client: stocke le jeton d'accès de l'utilisateur dans la session de navigateur ( géré par SDK commodément )
  5. Client: fait une demande à mon service web pour une ressource sécurisée en envoyant le long du jeton d'accès de l'utilisateur dans le en-tête autorisation + ID de l'utilisateur (dans l'en-tête personnalisé potentiellement)
  6. Serveur: , Lit-jeton d'accès utilisateur à partir d'en-tête de demande et initie une vérification par l'envoi d'une demande à l'debug_token API graphique fourni par Facebook
  7. Facebook: répond au serveur avec les informations du token d'accès utilisateur (contient appId et userId)
  8. Serveur: Complète vérification du token en comparant l'appId à ce qui est attendu (connu d'elle-même) et l'userId à ce qui a été envoyé à la demande du client
  9. Serveur: Répond au client avec la ressource demandée (en supposant que le plaisir d'autorisation de chemin)

j'imagine que les étapes 5-9 seraient répétées pour les requêtes ultérieures au serveur (alors que le token d'accès de l'utilisateur est valide – non expiré, révoqué du côté FB, app modification des autorisations, etc.)

voici un diagramme pour vous aider à suivre les étapes. S'il vous plaît comprendre que ce système est pas une application d'une seule page (SPA). Les services web mentionnés ci-dessus sont essentiellement des terminaux API qui servent les données JSON aux clients; ils ne servent pas HTML/JS/CSS (à l'exception des serveurs Web des clients).

Workflow diagram

Questions

  1. D'abord et avant tout, y a-t-il des lacunes évidentes / des chutes de fosse avec l'approche décrite basée sur ma préface et mes exigences?

  2. exécute-t-on une demande de sortie à Facebook pour vérifier le token d'accès (étapes 6-8 ci-dessus) par demande de client requis / recommandé?

    je sais à tout le moins, je dois vérifier le jeton d'accès provenant de la la demande du client. Cependant, l'approche recommandée pour des vérifications ultérieures après la première m'est inconnue. S'il y a des motifs typiques, j'aimerais en entendre parler. Je comprends qu'ils peuvent dépendre de l'application en fonction de mes exigences; cependant, je ne sais pas encore quoi chercher. Je ferai preuve de diligence dès que j'aurai une idée.

    par exemple, pensées possibles:

    • hachez le jeton d'accès + la paire d'identifiant d'utilisateur après la première vérification est complète et stocke-la dans un cache distribué (accessible par tous les serveurs web) avec expiration égale aux jetons d'accès. Sur les requêtes ultérieures des clients, hachez la paire de tokens d'accès + userId et vérifiez son existence dans le cache. Si présent, alors la demande est autorisée. Sinon, contactez L'API Facebook graph pour confirmer le token d'accès. Je suppose que cette stratégie pourrait être réalisable si J'utilise HTTPS (ce que je serai). Cependant, comment la performance comparer?

    • Les accepté de répondre à ce StackOverflow question , recommande la création d'un accès personnalisé jeton après la première vérification de l'Facebook jeton d'utilisateur est terminée. Le jeton personnalisé serait alors envoyé au client pour des requêtes ultérieures. Je me demande toutefois si cette solution est plus complexe que la précédente. Cela nécessiterait la mise en œuvre de mon propre fournisseur D'identité (ce que je veux éviter parce que je souhaitez utiliser des fournisseurs d'identité, en premier lieu,...). Est-ce là tout le mérite de cette proposition?

  3. est-ce que le champ signedRequest est présent sur la réponse à l'étape #3 ci-dessus (mentionné ici ), équivalent au paramètre de demande signé ici dans le flux ‘Games login’?

    ils semblent être suggérés comme équivalents depuis les anciens liens à ces derniers dans la documentation. Cependant, je suis surpris que la stratégie de vérification mentionnée sur la page des jeux ne soit pas mentionnée dans la ‘création manuelle d'un flux de connexion’ page de la documentation web.

  4. si la réponse à la question 3 est "oui", la même stratégie de confirmation de l'identité peut-elle être utilisée pour décoder la signature et la comparer à ce qui devrait être utilisé du côté du serveur?

    Decode & compare from FB docs

    je me demande si cela peut être utilisé au lieu de faire un appel sortant à l'API debug_token graph (étape 6 ci-dessus) pour confirmer le token d'accès comme recommandé ici :

    debug_token graph API from FB docs

    bien sûr, pour effectuer la comparaison côté serveur, la partie requête signée devra être envoyée avec la requête au serveur (étape 5 ci-dessus). Dans en plus de la faisabilité sans sacrifier la sécurité, je me demande comment la performance se comparerait à faire l'appel sortant.

  5. pendant que j'y suis, dans quel scénario / dans quel but, persisteriez-vous le jeton d'accès d'un utilisateur à une base de données par exemple? Je ne vois pas de scénario où j'aurais besoin de faire ça, cependant, il se peut que j'oublie quelque chose. Je suis curieux de savoir si certains scénarios communs pourraient être de susciter quelques pensées.

Merci!

59
demandé sur DIDIx13 2014-12-04 15:31:04

2 réponses

D'après ce que vous décrivez, je suggère d'utiliser un flux de connexion côté serveur comme décrit dans

pour que le token soit déjà sur votre serveur, et n'ait pas besoin d'être transmis par le client. Si vous utilisez des connexions non cryptées, cela peut représenter un risque pour la sécurité (par exemple pour les attaques de type "homme au milieu").

Les étapes seraient:

(1) gens de L'exploitation forestière dans

vous devez spécifier la permission que vous voulez obtenir des utilisateurs dans le paramètre scope . La requête peut être déclenchée uniquement via un lien normal:

GET https://www.facebook.com/dialog/oauth?
    client_id={app-id}
   &redirect_uri={redirect-uri}
   &response_type=code
   &scope={permission_list}

voir

(2) confirmer l'identité

GET https://graph.facebook.com/oauth/access_token?
    client_id={app-id}
   &redirect_uri={redirect-uri}
   &client_secret={app-secret}
   &code={code-parameter}

(3) inspecter la clé d'accès

vous pouvez inspecter le token comme vous l'avez déjà dit dans votre question via

GET /debug_token?input_token={token-to-inspect}
    &access_token={app-token-or-admin-token}

cela ne devrait être fait que du côté du serveur, car sinon vous rendriez votre jeton d'accès à l'application visible pour les utilisateurs finaux (ce n'est pas une bonne idée!).

voir

(4) extension du jeton d'accès

une fois que vous avez reçu le token (de courte durée), vous pouvez faire un appel pour prolonger le token comme décrit dans

comme suit:

GET /oauth/access_token?grant_type=fb_exchange_token
    &client_id={app-id}
    &client_secret={app-secret}
    &fb_exchange_token={short-lived-token}

(5) stockage des jetons d'accès

concernant le stockage des tokens sur le serveur, FB suggère de le faire:

(6) manipulation des jetons d'accès périmés

car FB ne vous avertit pas si un token a expiré (et si vous ne sauvegardez pas la date d'expiration et comparez-la à la timestamp courant avant de faire un appel), il est possible que vous receviez des messages d'erreur de FB si le token était invalide (après max. 60 jours). Le code d'erreur sera 190 :

{
  "error": {
    "message": "Error validating access token: Session has expired at unix 
                time SOME_TIME. The current unix time is SOME_TIME.", 
    "type": "OAuthException", 
    "code": 190
  }
}

voir

Si le jeton d'accès devient invalide, la solution est d'avoir la personne se connecte à nouveau, à ce moment-là vous pourrez faire des appels API en leur nom une fois de plus. Le flux de connexion que votre application utilise pour les nouvelles personnes devrait déterminer la méthode que vous devez adopter.

20
répondu Tobi 2014-12-04 13:31:34
  1. je ne vois aucune des lacunes flagrantes / fosse tombe, mais je ne suis pas un expert en sécurité.
  2. une fois que votre serveur a vérifié le token donné (étape 8), comme vous avez dit:

la réponse acceptée dans cette question StackOverflow recommande la création d'un token d'accès personnalisé après la première vérification du token utilisateur Facebook est terminée. Le jeton personnalisé serait alors envoyé au client pour des requêtes ultérieures. Je suis on se demande toutefois si cette solution est plus complexe que la précédente. Cela nécessiterait la mise en œuvre de mon propre fournisseur D'identité (ce que je veux éviter parce que je veux utiliser des fournisseurs d'identité externes en premier lieu...). Est-ce là tout le mérite de cette proposition?

à mon humble avis est le chemin à parcourir. J'utiliserais https://jwt.io / qui vous permet d'encoder des valeurs (l'userId par exemple) en utilisant une clé secrète. Alors votre client attache ce jeton pour chaque demande. Ainsi, vous pouvez vérifier la demande sans avoir besoin d'un tiers (vous n'avez pas besoin de requêtes de base de données ni). La bonne chose ici est qu'il n'y a pas besoin de stocker le jeton sur votre base de données.

vous pouvez définir une date d'expiration sur le token, pour forcer le client à s'authentifier à nouveau avec le Tiers quand vous le voulez.

  1. disons que vous voulez que votre serveur soit capable de faire quelque chose sans l'interaction client. Par exemple: Open graph histoires . Dans ce scénario, parce que vous devez publier quelque chose au nom de l'utilisateur, vous aurez besoin du token d'accès stocké sur votre base de données.

(Je ne peux pas vous aider avec les 3 et 4 questions, désolé).

1
répondu ilopezluna 2018-02-20 12:57:16