web-dev-qa-db-fra.com

À la recherche de suggestions pour la construction d’un lieu sécurisé REST API dans Ruby on Rails

Je commence à créer une API REST pour un projet sur lequel je travaille et cela m'a amené à faire une petite recherche sur le meilleur moyen de créer une API à l'aide de RoR. Je découvre assez rapidement que par défaut, les modèles sont ouverts sur le monde et peuvent être appelés via une URL en mettant simplement un ".xml" à la fin de l'URL et en passant les paramètres appropriés.

Alors, la question suivante est venue. Comment sécuriser mon application pour empêcher les modifications non autorisées? En faisant des recherches, j'ai trouvé quelques articles parlant de attr_accessible et attr_protected et de la façon dont ils peuvent être utilisés. L’URL particulière que j’ai trouvée en parlant a été postée en mai 2007 ( ici ). 

Comme pour toutes les choses Ruby, je suis sûr que les choses ont évolué depuis. Ma question est donc la suivante: est-ce toujours le meilleur moyen de sécuriser une API REST au sein du RoR?

Si non, que suggérez-vous dans un scénario "nouveau projet" ou "projet existant"?

65
Levi Rosol

Il existe plusieurs systèmes d'authentification des demandes d'API. Ils diffèrent de l'authentification normale fournie par les plug-ins, telle que restful_authentication ou acts_as_authenticated. Plus important encore, les clients ne maintiendront pas de sessions, il n'y a donc pas de concept de connexion.

Authentification HTTP

Vous pouvez utiliser l'authentification HTTP de base. Pour cela, les clients API utiliseront un nom d'utilisateur et un mot de passe habituels et le placeront simplement dans l'URL de la manière suivante:

http://myusername:[email protected]/

Je crois que restful_authentication prend en charge cette configuration immédiatement, de sorte que vous pouvez ignorer si quelqu'un utilise votre application via l'API ou via un navigateur.

L'un des inconvénients est que vous demandez aux utilisateurs d'indiquer clairement leur nom d'utilisateur et leur mot de passe dans chaque demande. En le faisant sur SSL, vous pouvez le rendre sûr.

Je ne pense cependant pas avoir jamais vu une API qui l'utilise. Cela me semble plutôt une bonne idée, d’autant plus que les schémas d’authentification actuels le supportent immédiatement, alors je ne sais pas quel est le problème.

Clé API

Un autre moyen simple d'activer l'authentification API consiste à utiliser des clés API. C'est essentiellement un nom d'utilisateur pour un service distant. Lorsque quelqu'un s'inscrit pour utiliser votre API, vous lui attribuez une clé API. Cela doit être passé avec chaque demande.

Un inconvénient est que si quelqu'un obtient la clé API de quelqu'un d'autre, il peut faire des demandes en tant qu'utilisateur. Je pense qu'en utilisant toutes les requêtes d'API comme protocole HTTPS (SSL), vous pouvez compenser ce risque.

Un autre inconvénient est que les utilisateurs utilisent les mêmes informations d'authentification (la clé API) partout où ils vont. S'ils veulent révoquer l'accès à un client API, leur seule option est de modifier leur clé API, ce qui désactivera également tous les autres clients. Cela peut être atténué en permettant aux utilisateurs de générer plusieurs clés d'API.

Clé API + Signature de la clé secrète

Obsolète (en quelque sorte) - voir OAuth ci-dessous

La signature de la demande avec une clé secrète est beaucoup plus complexe. C’est ce que font Amazon Web Services (S3, EC2, etc.). Essentiellement, vous donnez à l'utilisateur 2 clés: sa clé API (c'est-à-dire son nom d'utilisateur) et sa clé secrète (c'est-à-dire son mot de passe). La clé API est transmise à chaque demande, mais pas la clé secrète. Au lieu de cela, il est utilisé pour signer chaque demande, généralement en ajoutant un autre paramètre.

IIRC, Amazon accomplit cela en prenant tous les paramètres à la demande et en les classant par nom de paramètre. Ensuite, cette chaîne est hachée, en utilisant la clé secrète de l'utilisateur comme clé de hachage. Cette nouvelle valeur est ajoutée en tant que nouveau paramètre à la demande avant son envoi. Du côté d'Amazon, ils font la même chose. Ils prennent tous les paramètres (sauf la signature), les commandent et le hachage en utilisant la clé secrète. Si cela correspond à la signature, ils savent que la demande est légitime.

L'inconvénient est la complexité. Obtenir que ce schéma fonctionne correctement est une tâche ardue, à la fois pour le développeur de l'API et pour les clients. Attendez-vous à de nombreux appels d'assistance et à des courriels courroucés de la part des développeurs de clients qui n'arrivent pas à faire fonctionner les choses.

OAuth

Pour lutter contre certains problèmes de complexité liés à la signature clé + secrète, un standard appelé OAuth est apparu. A la base, OAuth est un exemple de signature clé + secrète, mais une grande partie est normalisée et a été incluse dans bibliothèques pour de nombreuses langues .

En général, il est beaucoup plus facile pour le producteur et le consommateur d'API d'utiliser OAuth plutôt que de créer votre propre système de clé/signature.

OAuth segmente également l'accès de manière inhérente, fournissant des informations d'identification d'accès différentes pour chaque consommateur d'API. Cela permet aux utilisateurs de révoquer l'accès de manière sélective sans affecter leurs autres applications consommatrices.

Spécifiquement pour Ruby, il existe un bijou OAuth qui fournit un soutien immédiat aux producteurs et aux consommateurs d’OAuth. J'ai utilisé ce bijou pour construire une API et également pour consommer des API OAuth et j'ai été très impressionné. Si vous pensez que votre application a besoin d'OAuth (par opposition au schéma de clé d'API plus simple), je peux facilement vous recommander d'utiliser la gem OAuth.

102
Micah

Comment sécuriser mon application pour empêcher modifications non autorisées?

attr_accessible et attr_protected sont tous deux utiles pour contrôler la possibilité d'effectuer des assignations en masse sur un modèle ActiveRecord. Vous voulez absolument utiliser attr_protected pour prévenir les attaques par injection de formulaire; voir Utilisez attr_protected ou nous vous piraterons .

De plus, afin d'empêcher quiconque d'accéder aux contrôleurs de votre application Rails, vous aurez certainement besoin d'un système d'authentification d'utilisateur et insérez un before_filter dans vos contrôleurs afin de vous assurer qu'un utilisateur autorisé effectue les tâches. avant d’autoriser l’exécution de l’action demandée par le contrôleur.

Consultez le Ruby on Rails Security Guide (élément du projet de documentation Rails) pour de nombreuses autres informations utiles.

7
Gabe Hollombe

Je suis confronté aux mêmes questions que vous en ce moment, car je construis également une REST - API pour une application Rails.

Je suggère de veiller à ce que seuls les attributs pouvant être modifiés par l'utilisateur soient marqués avec attr_accessible. Ceci établira une liste blanche d'attributs pouvant être assignés à l'aide de update_attributes.

Ce que je fais est quelque chose comme ça:

   class Model < ActiveRecord::Base  
       attr_accessible nil  
   end

Tous mes modèles en héritent, de sorte qu'ils sont obligés de définir attr_accessible pour tous les champs qu'ils souhaitent affecter en masse. Personnellement, j'aimerais qu'il y ait un moyen d'activer ce comportement par défaut (il peut y en avoir et je ne le sais pas).

Juste pour que vous sachiez que quelqu'un peut attribuer en masse une propriété non seulement à l'aide de REST api, mais également à l'aide d'un message standard.

3
jonnii

Une autre approche qui évite de construire beaucoup de choses vous-même consiste à utiliser quelque chose comme http://www.3scale.net/ qui gère les clés, les jetons, les quotas, etc. pour des développeurs individuels. Il effectue également des analyses et crée un portail de développement. 

Il existe un plugin Ruby/Rails plug-in API Ruby qui s'appliquera aux stratégies de gestion du trafic au moment où il arrive - vous pouvez l'utiliser conjointement avec le oAuth gem . Vous pouvez également nous en déposant du vernis devant l'application et en utilisant le vernis lib mod: Module API Varnish .

0
steve