RESTful et sécurité

FreyskeydFreyskeyd Membre
juin 2013 modifié dans Langages Web & serveurs #1

::

 

Bonjour à  tous,

 

 

Je sais que cette question a surement dû être posé des dizaines de fois sur des sujets relativement similaires, j'en suis même l'autre d'un sur RESTKit et l'authentification. 

 

N'étant pas exactement lié au framework RESTKit je préfère rouvrir un sujet pour plus de clarté si des personnes font une recherche sur le sujet.

 

Bref, pour ce qui est de ma question c'est surtout au niveau de la sécurité sur une api RESTful.

Je suis conscient que la première des protections est d'utiliser du SSL. Mais quand est-il de la suite?

 

Je ne suis pas un expert en sécurité informatique et je ne suis pas non plus un black hat donc excuser moi si je me trompe sur certains aspects. Je corrigerai le post en fonction des remarques.

 

 

Ce qui me pose problème sur le HTTPS c'est que les identifiants/mdp sont cryptés dans le HEADER. Un hacker pourrait donc facilement analyser une trame et les récupérer.

 

J'ai lu un article intéressant qui traite de la création d'une api REST par token qui selon moi semble plus solide qu'un HTTPS (je peux me planter..).


 


Pour résumer rapidement l'article, les étapes de création de création et de traitement d'une requête ce passe comme ceci : 


  1. Le client construit sa requête
  2. Le client ajoute à  sa requete le timestamp et l'uri de la requête
  3. Le client encode sa requête avec sa clé privé
  4. Le client envoi sa requête en passant en header, le hashage, sa clé public et la requête
  5. Le server reçoit la requête, regarde si le timestamp est valide (moins de 15minutes)
  6. Le server va chercher la clé privé lié à  la clé public qu'il a détecté
  7. Le server va hasher la requête qu'il a reçu avec le timestamp de la requête  la requête en elle même et l'uri d'accès
  8. Si le hash client et le hash serveur sont identiques, la requête est traité

 


Je trouve ce système plutôt fiable (j'attend l'avis d'expert là  dessus), mais quand est-il de la private key?


Dans l'article il dit de stocker la private key sur le server et chez le client (normal), mais stocker en dur, c'est à  dire une privateKey par application. Qui sera facilement corrompue par une décompilation de l'application.


 


La deuxième solution semble de créer un jeux de public/private key par utilisateur, mais comment ce passe le premier échange de cette privateKey?


 


L'utilisateur d'une application mobile, s'inscrit via l'application et récupère sa clé privé. Mais comment faire pour que cette clé privé soit protégé lors du transfert? Utilisé une clé privé stocker en dur uniquement pour la phase de création du compte?


 


J'aurai surement d'autre question qui me viendront, je n'ai pas encore tout exploré au niveau des possibilités mais je trouve cela intéressant de faire partager ça ici.


 


Cordialement,


Simon.


Mots clés:

Réponses

  • yoannyoann Membre

    Bon, après midi soleil et rosé mais je pense pouvoir répondre quand même :-)


    Le processus que tu décris ici (clef privée / publique) n'existe pas réellement en HTTP(s), et à  vrai dire tu mélange pas mal de truc comment le chiffrement de la communication et l'authentification des pairs.


     


    Je vais tâcher de reprendre les notions nécessaire dans leur ensemble.


     


    Avant de parler du processus d'authentification il faut parler du processus de chiffrement, et avant cela de HTTP en lui même.


     


    La chose à  garder en tête est que le protocole HTTP est stateless. Chaque requête au serveur est indépendante. Même si la requête nº1 est authentifié, il faut quand même authentifier la requête nº2 (peut importe la manière) pour que l'opération puisse fonctionner.


     


    Ensuite, HTTP en lui même n'est qu'un protocole en texte clair, très simple à  mettre en oe“uvre (d'où sa force). D'origine il ne permet pas d'authentifier les pairs ni même de chiffrer la communication.


     


    Pour palier cela, il existe HTTPS, qui n'est rien d'autre que HTTP sur TLS.


     


    TLS agit comme un tunnel de communication. Il se base sur des certificats X.509 (appelé à  tord certificats SSL/TLS) pour authentifier le serveur et dériver des clefs de chiffrement. Les deux parts de l'usage du TLS sont très importantes.


     


    La partie authentification du serveur par validation d'un tiers (la PKI X.509) permet d'être "certain" que le serveur avec lequel on parle est bien le serveur souhaité et non un rogue server monté par un attaquant. La partie chiffrement permet au serveur ainsi qu'au client de dériver une clef symétrique à  partir d'échange de seed aléatoire signé par le certificat du serveur. Le détail ici est intéressant, contrairement aux e-mail (avec S/MIME) par exemple, HTTPS utilise in fine une clef symétrique pour chiffrer les communications.


     


    À partir de là , on peut considérer que la communication est sécurisé. On est assuré que le serveur qui répond est bien celui que l'on cherche et l'échange entre lui et nous n'est ni écouté ni altéré par un tiers.


     


    Pour autant, seul le serveur a été authentifié ici, le client ne l'a pas encore été. Coté serveur on ne sait donc toujours pas à  qui on parles.


     


    Entre donc en jeu les protocoles d'authentification du client.


     


    Ici plusieurs écoles existent. Ma préféré reste la gestion de l'authentification par le protocole HTTP en lui même (IMHO c'est plus propre).


     


    Plusieurs type d'authentification existe dans ce cas :


    • Basic : identifiant et mot de passe envoyé en clair dans la communication (donc TLS obligatoire) ;
    • Digest : identification basé sur un dérivé de l'identifiant, du mot de passe, du royaume et d'éventuellement un seed (le bon compromis aujourd'hui) ;
    • X.509 : utilisation d'un certificat X.509 par client pour l'authentifier (complexe à  mettre en oe“uvre mais très secure, surtout si on génère un certificat par terminal utilisateur) ;
    • Spnego : utilisation de Kerberos pour authentifier, très puissant, très secure, très complexe, infaisable sur iOS aujourd'hui.

    Si on ne veut pas se prendre la tête, authentification Digest et c'est parti.


     


    Si on veut faire la fine bouche, authentification par certificat X.509 coté client. Le certificat peut être fournis à  l'avance par l'IT de la boite ou peut être généré par un service secondaire, accessible via HTTPS + Digest et permettant de signer un certificat généré par le client (jamais une clef privé ne doit circulé sur le réseau), une sorte de SCEP en somme. Le jour où le terminal est compromis, il suffit de révoquer son certificat, pas besoin de changer son mot de passe. C'est propre.


     


    Viens ensuite les bidouilles (foireuse?) qui font la même chose mais au niveau de l'application derrière le protocole de transport. On ré-invente la roue. 


     


    Dans ce genre de cas les bidouilles sont multiples, envois de l'identifiant et mot de passe dans le corps de la requête, en clair, en MD5, MD5+seed, truc bizarre... Ou comment faire du boulot que d'autres ont déjà  fait pour nous.


     


    Autre truc crade inventé par des gens qui ne savent pas se servir de l'existant, OAuth, qui reprend les principes d'OpenID qui lui même était une version simple (pour rigolo?) d'un SCEP sauf qu'on utilise un token au lieu d'un certificat pour authentifier le terminal.


     


    Si certain pensent que l'authentification par l'application est nécessaire pour la gestion des autorisations par exemple, c'est juste faux. Une fois authentifié, l'identifiant utilisé est fourni par le serveur HTTP à  son applicatif. Il n'y a donc aucune raison d'utiliser ces bricoles applicative par rapport à  quelque chose d'intégré dans HTTP.


     


    Vous l'aurez compris, je suis très loin d'être fan des infamies comme OAuth, c'est pour moi la preuve que les dev ne savent pas lire des RFC. Utilisez quelque chose d'intégré à  HTTP, de cette manière vous pourrez utiliser la gestion native de l'authentification dans NSURLConnection par exemple, pas besoin de vous prendre la tête.


     


    Voilà  pour mon point de vue sur la sécurité de HTTP. Le fait que ce soit du REST ou autre chose ne change rien à  la donne.


  • :: 


     


    Ok, merci pour toutes ces informations !


     


    J'ai encore du mal à  faire confiance pleinement à  HTTPS, dû à  un manque d'utilisation je pense.


     


    Le tunnel SSL entre le client et le serveur est réellement inviolable?


     


    Pour ce qui est du digest c'est un hash des identifiants avec l'uri de destination ?


     


    Le hachage ce fait-il lors de la construction de la requete? Ou est-ce géré par le protocol?


     


    J'ai du mal à  voir le processus complet en réalité.


     


    Merci à  toi !


  • yoannyoann Membre

    Le protocole TLS est sécurisé mais il repose sur le fonctionnement des PKI de certificats X.509. Si l'utilisateur accepte un certificat invalide ou si un attaquant arrive à  placer dans son téléphone une clef racine d'une autorité pirate, alors toute la sécurité disparait.


     


    Cependant dans le cas d'un applicatif, c'est toi qui est aux commande, tu peux très bien hardcodé certains choses (comme le nom de l'autorité ayant délivré ton certificat) et également refuser tout faux certificats.


     


    Concernant le Digest, tu as l'algo ici http://en.wikipedia.org/wiki/Digest_access_authentication


    L'opération se fait à  la construction de la requête ainsi que durant l'échange avec le serveur (il y a un aller-retour avant d'obtenir la ressource demandé), mais c'est transparent pour toi, tu as juste à  utiliser NSCredentials.


     


    Même si tu as du mal à  comprendre le processus, place plutôt du temps à  l'appréhender plutôt qu'à  réinventer la roue. TLS est vraiment mature maintenant, ça fait des années qu'on s'en sert. Ce sera toujours plus fiable qu'un truc neuf de ton imagination (surtout que tu ne semble pas à  l'aise avec les notions élémentaires de sécurité, aucune offense ici).


  • ::


     


    Justement j'ai entendu dire que les organismes qui gère ces certificats ne sont pas irréprochable (c'est peut-être de la connerie).


     


    Y'en a t'il des plus fiables que d'autres ?


     


    Pour ce qui est de l'API je pense que le combo TLS + Digest est, comme tu l'as dis, le plus adapté.


     


    A++


  • yoannyoann Membre

    Effectivement, certain laissent à  désirer. Tu peux aussi monter ta propre PKI (de toute manière nécessaire pour de l'authentification client par certificat).


  • ::


     


    Après quelques recherches je ne trouve pas grand chose en rapport avec la création de PKI.


    C'est quel genre de processus?


     


    A+ et merci


  • yoannyoann Membre

    T'as un article par là  si tu veux http://blog.inig-services.com/archives/493 mais c'est assez lourd, c'est fait pour de l'humain.


     


    Dans ton cas tu peux certainement te baser sur openssl directement https://pki-tutorial.readthedocs.org/en/latest/


  • FreyskeydFreyskeyd Membre
    juillet 2013 modifié #9

    Salut,


     


    Petite question en supplément sur le digest.


     


    Si j'ai bien compris il faut en gros pour chaque Requête faire deux requêtes, une pour le récupérer le nonce du serveur et l'autre pour la resource voulu.


     


    Dans un premier, le nonce du serveur change à  chaque requete renvoyant un 401, mais est-ce lié à  l'utilisateur? unique au serveur? En gros si j'ai X client faisant des requetes en concurrence :


     


    Client 1 réseau pourri, Client 2 réseau wifi.


     


    Le client 1 demande le nonce : a766f996fa716e4d4592943b5762c7395


    Le client 2 demande le nonce : a766f996fa716e4d4592943b5762c7395


    Le client 2 demande la ressource /user/bisous mais il n'est pas auth -> le nonce serveur change en be09d67c532a3a022943b5762c7395


    Le client demande la resource /user/bisous auquel il a accès mais le nonce serveur est different de celui qu'il soumet.


     


    Que ce passe t'il dans ce cas là ?


     


    Seconde question, je vois un cnonce (client nonce je présume) mais j'ai du mal à  comprendre son utilité. est-il vraiment utile?


     


    Dernière question, la récupération du nonce serveur est-elle obligatoire à  chaque requete?


     


    Si je dois récupérer une vingtaine de resource pour peupler une liste il y aura donc 40 requetes serveurs ?


     


     


    Pour le moment je construits ma réponse comme ceci :


     


    Je prend en compte le fais que j'ai récupérer le nonce du serveur ainsi que le realm.


     


    Tien le realm doit-il utiliser celui du serveur (renvoyé par la requete?) ou stocker en dur dans le device?



    A1 = SHA1(username:realm:secret)

    A2 = SHA1(VERB:URI)

    response = SHA1( A1 : nonce : A2 )

    Je pense qu'il manque des paramètres...


     


    Merci de m'avoir lu !


  • Tu as lu les exemples de session de la page Wikipedia ? http://en.wikipedia.org/wiki/Digest_access_authentication


     


    Les nonces ne sont que des vecteurs, ils sont fournis par le serveur et retransmit par le client lors de la réponse. HTTP est stateless, ne l'oublis pas :-)


  • FreyskeydFreyskeyd Membre
    juillet 2013 modifié #11

    Oui je les ai lu, mais il montre un fonctionnement où l'ont demande à  l'utilisateur de renseigné username/mdp après la réception d'une page contenant le realm et le nonce.


     


    Du coup si j'enleve toute cette partie (nonce/cnonce) la sécurité de mon interaction diminue...


     


    Je ne trouve pas grand chose au niveau des exemples ils se ressemblent un peu tous.


  • Je ne comprends pas la question. Pourquoi tu enlève toute cette partie si justement tu essaye d'implémenter du DIGEST ?


  • Je me pose des questions au niveau de la fluidité sur des réseaux dégradés, deux requêtes serveur au lieu d'une c'est ce qui me fait peur..


     


    Et quand est-il du nonce-count? Comment dois-je le gérer côté serveur?


     


    Bref je ne vois pas trop comment utiliser ce Nonce server, dois-je le générer à  la volé à  chaque requete le demandant?


    Dois-je le lié à  un utilisateur?

  • Deux requêtes mais une seule connexion TCP si tu utilise les bons outils.


     


    Par contre je ne comprend toujours pas pourquoi tu t'emmerde à  réinventer la roue là ... NSURLConnection implémente déjà  ce mécanisme comme il faut pour le client et pour le serveur tu n'as qu'à  te reposer sur le serveur HTTP en lui même qui sait déjà  faire ça non ?


  • Je n'essai pas de réinventer la roue, j'essai de comprendre comment cela fonctionne :)


     


    Pour ce qui est du serveur j'utilise un petit framework (slim) qui utilise un middleware pour le digest. 


     


    Si je passe par HTTP je pourrai définir des routes ayant besoin d'une authentification et d'autres non?



  •  


    Si je passe par HTTP je pourrai définir des routes ayant besoin d'une authentification et d'autres non?




     


    C'est le principe oui. http://httpd.apache.org/docs/current/howto/auth.html


     


    Une fois l'authentification faites sur ta route, tu peut récupérer l'identifiant de l'utilisateur dans les header ou un truc du genre au niveau de ton CGI pour pouvoir faire la partie autorisation éventuellement (et tu renvois un 403 si ton code métier refuse l'accès à  l'URI pour l'utilisateur en question).

Connectez-vous ou Inscrivez-vous pour répondre.