Sécuriser l’API REST 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!
  • L’utilisateur veut stocker / mettre à jour des données … woah wait up! Qui es-tu, peux-tu faire ça?

Je voudrais le construire une fois et permettre à une application Web, à une application Android ou à une application iPhone de 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 firebase database, qui a un atsortingbut de notation (entier de 1 à 5).

Si je comprends bien REST, j’implémenterais une requête GET en utilisant le langage de mon choix qui renvoie csv, xml ou json comme ceci:

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

Disons que nous choisissons JSON que nous retournons:

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

Cela convient aux API publiques. Je reçois cette partie.

Je me pose des questions: comment puis-je combiner cela avec un modèle de sécurité? Je suis habitué à la sécurité des applications Web où un état de session identifie mon utilisateur à tout moment pour 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 une mauvaise solution dans ce cas.

Je vais essayer d’utiliser un autre exemple en utilisant le même article / la même notation.

Si l’utilisateur “JOE” veut append une note à un élément

Cela pourrait être fait en utilisant:

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

À ce stade, je veux stocker les données en disant que “JOE” a donné au produit {id} une note de {atsortingbuéRating}.

Question: Comment savoir si la demande provient de “JOE” et non de “BOB”.

De plus, que se passe-t-il si des données plus sensibles, telles que le numéro de téléphone d’un utilisateur, sont utilisées?

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

1) Utilisez la fonctionnalité intégrée de HTTP pour s’authentifier à chaque requête, qu’il s’agisse de HTTP simple ou de HTTPS.

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

 https://joe:joepassword@example.com/product/addrating/{id}/{givenRating}/ 

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

3) Utilisez de toute façon un cookie et cassez la partie sans état de REST.

La seconde approche me semble meilleure, mais je me demande si je dois vraiment réinventer tout ça? Hashing, stockage, génération des clés, etc. tout seul?

Cela ressemble beaucoup à l’utilisation d’une session dans une application Web classique et à la réécriture de la stack entière, ce qui pour moi signifie généralement “vous vous trompez”, en particulier en matière de sécurité.

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

Modifier 5 ans plus tard

Utilisez OAuth2!

La version précédente

Non, il n’est absolument pas nécessaire d’utiliser un cookie. Il n’est pas deux fois plus sécurisé que HTTP Digest, OAuth ou AWS (qui n’est pas difficile à copier).

La façon dont vous devriez regarder un cookie est que c’est 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 tant que tels, tant que le contenu du cookie de session n’influence pas le contenu de la ressource que vous retournez du serveur.

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

Ne vous inquiétez pas pour être “RESTful”, inquiétez-vous de la sécurité. Voici comment je le fais:

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

Etape 2: Si les informations d’identification sont récupérées, renvoyez une empreinte digitale, un identifiant de session, etc., et insérez-les dans la mémoire partagée pour une récupération rapide ultérieure ou utilisez une firebase database si cela ne vous dérange pas .

Étape 3: Ajoutez un appel de point d’entrée en haut de chaque script de service Web qui valide l’empreinte et l’identifiant de session pour chaque demande de service Web.

Étape 4: Si les empreintes digitales et l’identifiant de session ne sont pas valides ou ont expiré, redirigez-les vers l’authentification.

LIS ÇA:

Authentification RESTful

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 – les jetons Web JSON peuvent également être utiles.

La version précédente

Utilisez un cookie quand même et brisez la partie sans état de REST.

N’utilisez pas de sessions, avec des sessions votre service REST ne sera pas très évolutif … Il y a 2 états ici: l’état de l’application (ou l’état ou la session du client) et l’état de la ressource. L’état de l’application contient les données de session et est géré par le client REST. L’état de la ressource contient les propriétés et les relations de la ressource 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 de la ressource. Si la quantité de données augmente avec le nombre de sessions actives, alors elle appartient à 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 permissions 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 créer, par exemple, un cookie HTTP côté serveur qu’il peut partager avec le service REST via CORS. La seule chose qui compte pour 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 REST côté client, cela peut être fait avec SSL + HTTP auth. Dans ce cas, vous pouvez créer un cache d’ credentials -> (identity, permissions) sur le serveur pour accélérer l’authentification. Sachez que si vous effacez 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 ceci avec des sessions: si vous effacez le magasin de session, alors les utilisateurs obtiendront un status: 401 unauthorized réponse status: 401 unauthorized
  • Si vous écrivez un client REST côté serveur et que vous envoyez des facteurs d’identification au service REST via curl, vous avez deux choix. Vous pouvez également utiliser http auth ou utiliser un gestionnaire de session dans votre client REST mais pas dans le service REST.
  • Si une personne non approuvée écrit votre client REST, vous devez écrire une application pour authentifier les utilisateurs et leur donner la possibilité de décider s’ils souhaitent accorder des permissions à différents clients ou non. Oauth est une solution déjà existante pour cela. Oauth1 est plus sécurisé, oauth2 est moins sûr mais plus simple, et je suppose qu’il existe plusieurs autres solutions à ce problème … Vous n’avez pas à le réinventer. Il existe des solutions d’authentification et d’autorisation complètes utilisant oauth, par exemple: le serveur d’identité wso .

Les cookies ne sont pas nécessairement mauvais. Vous pouvez les utiliser de manière REST jusqu’à ce qu’ils conservent l’état du client et que le service ne détienne que l’état de la ressource. Par exemple, vous pouvez stocker le panier ou les parameters de pagination préférés dans les cookies …