Bonjour.

Je reviens vers vous afin d'avoir vôtre avis sur la sécurité de mon application angular et de l'API Rest Laravel qui va avec.

J'en entendu parler du header Access-Control-Allow-Origin qui permettrais de bloquer une requête provenant d'une autre domaine que le mien. Seulement je ne comprend pas encore très bien sa façon de fonctionner.

Es-ce suffisant ? Certainement que non, car la plus part des sites construits avec un client qui fait des requêtes ajax ont un systèle de clé de sécurité.

Je me suis donc aussi renseigné sur ce fait, j'ai trouvé des systèmes basé sur une clé publique et privée.
J'ai donc essayé d'imaginer un système pour m'assurer que chaque requête provient bien du client angular.
Je vais tenter de vous l'expliquer avec des valeurs très simple, biensur j'utiliserais des valeurs de clé et un cryptage plus complexe.

Côté client :

    var cle_prive = 2;
    var cle_publique = Math.floor((Math.random() * 10) + 1); // Un nombre entre 1 et 10
    var cryptage = cle_prive + cle_publique
    $http.post('adresse de l'api', {cle_publique: cle_publique, cryptage: cryptage});

On envoie donc la clé_publique générée et le résultat du cryptage a l'API

Côté serveur :

    $cle_prive = 2;
    if($_POST['cle_publique'] + $cle_prive == $_POST['cryptage']){
        // La clé privé utilisé pour générer le cryptage sur le client est la même que sur le serveur donc c'est bien le client angular qui a envoyé la requête
    }

Je rapelle que les valeur et le cryptage serront bien plus complexe, sinon c'est un peu simple de trouver la clé privée

Voila voila, j'aimerai votre avis sur cette manière de faire, et si vous en connaissez d'autre je suis ouvert a toutes vos idées.

21 réponses


Bonjour olcahmp,

En effet, il est important d'ajouter une clé propre à l'application, principalement pour prévenir d'une attaque "Man In The Middle".

La méthode que tu utilises n'est pas mauvaise (d'ailleurs utilisée par Amazon il me semble) mais te contentes-tu de ça?

Un système de clés c'est bien mais, sûrement pas suffisant, pour moi l'encryption des données est prioritaire (forcé le https). Et pourquoi ne pas plutôt utilisé authentification sécuriséee par OAuth (il y a plein de documentations, si tu es anglophone, voilà un article qui explique le principe: https://stormpath.com/blog/secure-your-rest-api-right-way/ et voici un package laravel : https://packagist.org/packages/artdarek/oauth-4-laravel).

Pour conclure, selon moi une encryption SSL et OAuth sont les plus appropriés pour ce que tu veux faire. Bien que ton système peut faire l'affaire, je suis adepte du: "Ne pas refaire ce qui existe déjà et fonctionne très bien".

Bonjour,

Il me semble qu'il manque une information importante dans ce post. Que dois-tu sécuriser? Quel type de données ? Quel est la sensibilité des données?

La mise en place d'une couche de sécurité et de son niveau de sécurité dépend fortement du contexte. C'est quelque chose d'impactant en terme de perfs, coût, contraintes d'architecture etc... Mettre en place une rolls quand on a besoin d'une 2 CV n'est pas nécessaire.

Plusieurs solutions sont possibles, mais dépendent également du contexte.
Quand tu dis Rest, c'est donc bien stateless?

olchanp
Auteur

Antho :
C'est un petit jeu par navigateur, les données sont donc évidement les identifiants des joueurs, mais aussi leurs actions, si n'importe qui peut lancer des requêtes sans passer par mon client, c'est la porte ouverte aux bots.

sudovim:
"Tu fais juste une addition, je ne comprends même pas à quel moment tu as pu imaginer que ton code pouvait protéger quoi que ce soit."
J'ai préciser plusieurs fois, que ce ne serrait pas une addition ni des valeurs aussi simple qu'un chiffre qui serviraient ... ce que j'ai proposé était un exemple.

"donc doit rester côté serveur et jamais côté client."
Je me suis dit que dans un fichier js minifié il serrait compliqué de trouver la clé, mais tu as certainement raison sur ce point.

"Tu peux verifier que les requêtes proviennent d'un utilisateur autorisé mais pas qu'elle proviennent d'un type de client précis."
Si la clé est contenue dans le client angular que j'ai codé, je peux grâce a mon système que le client a bien la bonne clé, donc que c'est le mien.

Ton post n'a d'autre ambition que de critiquer sans proposer de solution ... ce qui n'a pas d'intéret pour moi.

Akronos :

Etant moyennement anglophone, OAuth m'avais parru bien compliqué a mettre en place, mais si tu me le conseille je vais me pencher sur cette solution.
Merci pour ton intervention constructive et les deux liens ;)

PS: Le header Access-Control-Allow-Origin sert a quelque chose dans mon cas ?

Quel est la volumétrie ? Combien de joueurs? Combien de requête par secondes en période de pics?

olchanp
Auteur

Je n'en ai aucune idée malheuresment, c'est un projet amateur, je ne suis même pas sûr d'être assez compétant pour le finir ...

Comment est gérer l'authentification ? l'utilisateur s'inscrit ?

olchanp
Auteur

Oui il doit s'inscrire

Dans ce cas, on pourrait imaginer un système de token changeant à chaque connexion (ou à chaque appel de l'api).
Si c'est suffisant et que les perfs ne sont pas réellement impactées..

Sinon il y a des protocoles comme auth mais je les trouve un peu fort parce qu'ils sont habituellement destinés à sécuriser des échanges dans des cadres de SSO, plusieurs serveurs, plusieurs domaines..

Par contre j'ai une question .. l'api est accessible publiquement sans authentification préalable ??

olchanp
Auteur

Concretement, comment organiserais tu ce système de token ?

Une petite partie de l'API est accessible sans authentification, j'ai besoin de récupérer certaines info a afficher sur le "portail" du jeu, qui est une application angular a part entière et qui permet la connexion, inscription, contact ... Sinon tout le reste de l'API est accessible uniquement aux utilisateurs connectés.

Pour le moment, je n'ai pas codé grand chose, et j'utilise seulement l'authentification fourni par laravel, mais ce n'est pas sécurisé, n'importe qui pourrait envoyer des requête a mon serveur.

Tu veux sécuriser quelle partie ? la publique ?

olchanp
Auteur

Il faudrais sécuriser le tout non ? La partie publique doit envoyer la requête de connexion, si tout est bon elle redirige vers l'application angular du jeu.

Comment tu géres une fois l'utilisateur connecté?
la session ??

olchanp
Auteur

Akronos :

J'ai essayé d'installer la dépendance pour laravel que tu m'a indiqué, j'ai l’impression qu'elle permet surtout de se connecter a des services utilisant déjà une API Oauth comme Facebook ou Google et pas de créer sa propre API. Peux tu m'éclairer ?

Antho :

Oui je gère avec la session pour le moment, je comptais attendre de savoir quel type de sécurité j'allais avoir pour trouver comment faire la liaison entre le portail et le jeu.

olchanp
Auteur

"Si tu mets la clé privée côté client ta protection ne sert absolument à rien."

Sur ce diagramme de OAuth :

On voit que le client possède bien un client_id et un client_secret, donc il faut quand même qu'une clé soit disponible directement sur le client. Mais je me demande comment faut-il la faire passer au serveur sans que l'utilisateur puiise la voir.

Je ne comprends pas trop .
Tu dis utiliser les sessions ? (donc tu n'es pas vraiment en REST)

Tu as bien qu"un seul serveur ?

Une personne non connecté sur le jeu va donc se faire refuser par l'api (sauf pour éventuellement les méthodes login et logout) ?

J'ai un pti peu de mal à situer le besoin..

Oauth ne me semble pas adapter au cas

olchanp
Auteur

Effectivement j'utilise l'authentification de laravel : ICI et donc les sessions
J'ai un seul serveur, et deux applications angular ( je n'ai pas trouver de moyen plus simple de faire un portail qui puisse dans le futur donner accès a deux univers de jeu, donc deux serveur, même si ce n'est pas d'actualité pour le moment. )

Il y a donc le portail, qui est chargé d'authentifier l'utilisateur, puis de l'envoyer vers l'application angular ou on peut jouer.
L'utilisateur n'a donc accès qu'aux fonctions de connexion et de déco ( + une fonction pour tester les sessions qui disparaîtra )

    $this->beforeFilter('auth', array('except' => array('postLogin', 'postUser', 'postTest')));

Mon besoin est donc de m'assuer que les requêtes que recoit le serveur, proviennent bien d'une de mes deux applications angular, et pas d'une page web crée par un hacker, qui pourrant envoyer en ajax des requêtes automatiques pour par exemple attaquer un autre joueur.
Si aucune vérification n'est faite, il est facile d'utiliser cette page comme un robot, qui va jouer pour nous et donc nous donner un avantage contre les autres joueur.

un hacker qui serait connecté?
Dans ce cas, c'est vain ... parce que si il balance les requêtes vers ton api depuis ton site , comment tu vas traiter?

olchanp
Auteur

Le problème est justement qu'il passe bien par mon site, qui oblige l'utilisateur a cliquer sur le bouton attaquer par exemple, et pas un script qui balance des requête automatisés ...

et s'il lance son script js depuis ta page?

Re olchanp, désolé je n'étais pas dispo ce week-end.

En effet, le lien que je t'ai filé est fait pour se connecter à des APIs comme Facebook, Google, etc (mais je pense qu'il est quand même possible de créer une classe perso pour ta propre API). Sache qu'il y a quand même pas mal d'autres pacquets qui gèrent OAuth (HybridAuth, par exemple, correspond plus à tes attentes je pense : http://hybridauth.sourceforge.net (c'est encore en Anglais, sorry, mais tu verras avec le temps tu comprendras de mieux en mieux l'Anglais (c'est presque vital))).

Pour toutes tes questions de clés/tokens, sache que tu n'es pas le premier à te les poser. Je te file quelques liens (Français en plus) de personnes qui se sont posées les mêmes questions. En espérant que les réponses t'aident:
http://openclassrooms.com/forum/sujet/utiliser-oauth-pour-cree-une-api-80736
http://la-cascade.ghost.io/api-authentification/

De la doc Française sur OAuth:
http://blog.netapsys.fr/oauth-comment-ca-marche/comment-page-1/
http://www.bubblecode.net/fr/2013/03/10/comprendre-oauth2/

Pour l'histoire du header Acces-Control-Allow-Origin, il doit être fournit pour chaque requête qui donne accès à une ressource. T'as un peu de doc sur le MDN (https://developer.mozilla.org/fr/docs/HTTP/Access_control_CORS#Access-Control-Allow-Origin), là aussi tu dois pourvoir en trouver pas mal sur Google (qui répondront plus à tes questions) avec une recherche du type : "API utiliser Acces-Control-Allow-Origin".

NB: Au fait, sais-tu que Laravel permet déjà la création d'un token pour protéger des cross-sites requests ("requêtes de sites externes") ?
http://laravel.com/docs/4.2/security#protecting-routes

olchanp
Auteur

Merci beaucoup du temps passé pour m'aider, t'es super ;)
Je ne vais pas avoir le temps de m'y pencher pour l'instant, mais dès que je pourrais j'irais voir tout ça.