web-dev-qa-db-fra.com

Sécuriser REST API sans réinventer la roue

Lors de la conception de l'API REST, est-il courant d'authentifier un utilisateur en premier?

Le cas d'utilisation typique que je recherche est:

  • L'utilisateur veut obtenir des données. Bien sûr, nous aimons partager! Obtenez une clé API publique et lisez la suite!
  • L'utilisateur veut stocker/mettre à jour les données ... woah attendez! qui êtes-vous, pouvez-vous faire cela?

Je voudrais le construire une fois et permettre par exemple une application web, une application Android ou une application iPhone pour l'utiliser).

Une API REST semble être un choix logique avec des exigences comme celle-ci

Pour illustrer ma question, je vais utiliser un exemple simple.

J'ai un élément dans une base de données, qui a un attribut rating (entier 1 à 5).

Si je comprends bien REST correctement, j'implémenterais une requête GET en utilisant la langue de mon choix qui retourne csv, xml ou json comme ceci:

http://example.com/product/getrating/{id}/

Disons que nous choisissons JSON, nous revenons:

{
  "id": "1",
  "name": "widget1",
  "attributes": { "rating": {"type":"int", "value":4} }
}

C'est très bien pour les API publiques. Je comprends cette partie.

Là où j'ai des tonnes de questions, comment puis-je combiner cela avec un modèle de sécurité? Je suis habitué à la sécurité des applications Web où j'ai un état de session identifiant mon utilisateur à tout moment afin que je puisse contrôler ce qu'il peut faire, peu importe ce qu'il décide de m'envoyer. Si je comprends bien, ce n'est pas RESTful, ce serait donc une mauvaise solution dans ce cas.

Je vais essayer d'utiliser un autre exemple en utilisant le même article/note.

Si l'utilisateur "JOE" souhaite ajouter une note à un élément

Cela pourrait être fait en utilisant:

http://example.com/product/addrating/{id}/{givenRating}/

À ce stade, je souhaite stocker les données indiquant que "JOE" a donné au produit {id} une note de {givenRating}.

Question: Comment puis-je savoir que la demande provient de "JOE" et non de "BOB".

De plus, que faire si c'était pour des données plus sensibles comme le numéro de téléphone d'un utilisateur?

Ce que j'ai jusqu'à présent, c'est:

1) Utilisez la fonction intégrée de HTTP pour vous authentifier à chaque demande, soit en HTTP simple, soit en HTTPS.

Cela signifie que chaque demande prend désormais la forme de:

https://joe:[email protected]/product/addrating/{id}/{givenRating}/

2) Utilisez une approche comme S3 d'Amazon avec clé privée et clé publique: http://www.thebuzzmedia.com/designing-a-secure-rest-api-without-oauth-authentication/

3) Utilisez quand même un cookie et cassez la partie apatride de REST.

La deuxième approche me semble meilleure, mais je me demande si je dois vraiment réinventer tout cela? Hachage, stockage, génération des clés, etc. tout seul?

Cela ressemble beaucoup à l'utilisation de session dans une application Web typique et à la réécriture de la pile entière vous-même, ce qui signifie généralement pour moi "vous vous trompez", en particulier lorsqu'il s'agit de sécurité.

EDIT: Je suppose que j'aurais dû aussi mentionner OAuth.

73
jfrobishow

Modifier 5 ans plus tard

Utilisez OAuth2!

version précédente

Non, il n'est absolument pas nécessaire d'utiliser un cookie. Ce n'est pas à moitié aussi sûr que HTTP Digest, OAuth ou AWS d'Amazon (qui n'est pas difficile à copier).

La façon dont vous devriez regarder un cookie est qu'il s'agit d'un jeton d'authentification autant que Basic/Digest/OAuth/selon le cas, mais moins approprié.

Cependant, je ne pense pas que l'utilisation d'un cookie va à l'encontre des principes RESTful en soi , tant que le contenu du cookie de session n'influence pas le contenu de la ressource que vous renvoyez du serveur.

Les cookies sont mauvais, arrêtez de les utiliser.

21
Evert

Ne vous inquiétez pas d'être "RESTful", souciez-vous de la sécurité. Voici comment je le fais:

Étape 1: l'utilisateur accède au service d'authentification avec des informations d'identification.

Étape 2: Si les informations d'identification sont récupérées, renvoyez une empreinte digitale, un identifiant de session, etc., et placez-les dans la mémoire partagée pour une récupération rapide plus tard ou utilisez une base de données si cela ne vous dérange pas d'ajouter quelques millisecondes au délai d'exécution de votre service Web .

Étape 3: ajoutez un appel de point d'entrée en haut de chaque script de service Web qui valide l'empreinte digitale et l'ID de session pour chaque demande de service Web.

Étape 4: si l'empreinte digitale et l'ID de session ne sont pas valides ou ont expiré, redirigez vers l'authentification.

LIS ÇA:

Authentification RESTful

21
Daniel Pereira

Modifier 3 ans plus tard

Je suis entièrement d'accord avec Evert, utilise OAuth2 avec HTTPS et ne réinvente pas la roue! :-)

Par des API REST plus simples - non destinées aux clients tiers - jetons Web JSON peut également être bon.

Version précédente

Utilisez quand même un cookie et cassez la partie apatride de REST.

N'utilisez pas de sessions, avec des sessions votre service REST ne sera pas bien évolutif ... Il y a 2 états ici: l'état de l'application (ou l'état du client ou les sessions) et l'état des ressources. L'état de l'application contient les données de session et elles sont gérées par le client REST. L'état des ressources contient les propriétés et les relations des ressources et est géré par le service REST. Vous pouvez décider très facilement si une variable particulière fait partie de l'état de l'application ou de l'état des ressources. Si la quantité de données augmente avec le nombre de sessions actives, elles appartiennent à l'état de l'application. Ainsi, par exemple, l'identité de l'utilisateur par la session en cours appartient à l'état de l'application, mais la liste des utilisateurs ou des autorisations utilisateur appartient à l'état de la ressource.

Le client REST doit donc stocker les facteurs d'identification et les envoyer avec chaque demande. Ne confondez pas le client REST avec le client HTTP. Ils ne sont pas les mêmes. Le client REST peut également être côté serveur s'il utilise curl, ou il peut créer par exemple un cookie http uniquement côté serveur qu'il peut partager avec le service REST via CORS. La seule chose qui importe que le service REST doit s'authentifier à chaque demande, vous devez donc envoyer les informations d'identification (nom d'utilisateur, mot de passe) à chaque demande.

  • Si vous écrivez un client côté client REST, cela peut être fait avec l'authentification SSL + HTTP. Dans ce cas, vous pouvez créer un cache credentials -> (identity, permissions) sur le serveur pour accélérer l'authentification. Soyez conscient que si vous videz ce cache et que les utilisateurs envoient la même demande, ils obtiendront la même réponse, mais cela prendra un peu plus de temps. Vous pouvez comparer cela avec des sessions: si vous effacez le magasin de sessions, les utilisateurs obtiendront une réponse status: 401 unauthorized ...
  • Si vous écrivez un client côté serveur REST et que vous envoyez des facteurs d'identification au service REST via curl, vous avez 2 choix. Vous pouvez également utiliser l'authentification http ou vous pouvez utiliser un gestionnaire de sessions dans votre client REST mais pas dans le service REST.
  • Si quelqu'un non fiable écrit votre client REST, vous devez alors écrire une application pour authentifier les utilisateurs et leur donner la disponibilité pour décider s'ils veulent accorder ou non des autorisations à différents clients. Oauth est une solution déjà existante pour cela. Oauth1 est plus sécurisé, oauth2 est moins sécurisé mais plus simple, et je suppose qu'il existe plusieurs autres solutions à ce problème ... Vous n'avez pas à réinventer cela. Il existe des solutions complètes d'authentification et d'autorisation utilisant oauth, par exemple: le serveur d'identité wso .

Les cookies ne sont pas nécessairement mauvais. Vous pouvez les utiliser de manière RESTful jusqu'à ce qu'ils détiennent l'état client et que le service ne conserve que l'état des ressources. Par exemple, vous pouvez stocker le panier ou les paramètres de pagination préférés dans les cookies ...

8
inf3rno