web-dev-qa-db-fra.com

Comment protéger une REST uniquement pour les applications mobiles de confiance

Comment puis-je m'assurer que mon REST ne répond qu'aux demandes générées par des clients de confiance, dans mon cas mes propres applications mobiles? Je veux empêcher les demandes indésirables provenant d'autres sources. Je ne veux pas aux utilisateurs de remplir une clé de série ou autre, cela doit se produire en coulisses, lors de l'installation, et sans aucune interaction utilisateur requise.

Pour autant que je sache, HTTPS sert uniquement à valider le serveur avec lequel vous communiquez, c'est à dire avec qui il est. Je vais bien sûr utiliser HTTPS pour crypter les données.

Existe-t-il un moyen d'y parvenir?

pdate: L'utilisateur peut effectuer des actions en lecture seule, qui ne nécessitent pas que l'utilisateur soit connecté, mais ils peuvent également effectuer des actions d'écriture, qui nécessitent que l'utilisateur soit connecté (Authentification par accès Jeton). Dans les deux cas, je souhaite que l'API réponde aux demandes provenant uniquement d'applications mobiles de confiance.

L'API sera également utilisée pour l'enregistrement d'un nouveau compte via l'application mobile.

pdate 2: Il semble qu'il y ait plusieurs réponses à cela, mais honnêtement, je ne sais pas laquelle signaler comme réponse. Certains disent que cela peut être fait, certains disent que non.

100
Supercell

Vous ne pouvez pas.

Vous ne pouvez jamais vérifier une entité, n'importe quelle entité, que ce soit une personne, un client matériel ou un client logiciel. Vous pouvez seulement vérifier que ce qu'ils sont dire vous avez raison, puis assumez l'honnêteté.

Par exemple, comment Google sait-il que c'est je suis connecté à mon compte Gmail? Ils me demandent simplement un nom d'utilisateur et un mot de passe, vérifient que, puis assumez l'honnêteté car qui d'autre aurait cette information? À un moment donné, Google a décidé que cela ne suffisait pas et a ajouté une vérification du comportement (à la recherche d'un comportement étrange), mais qui s'appuie toujours sur le personne pour faire le comportement , puis valider le comportement .

C'est exactement la même chose avec la validation du Client. Vous pouvez uniquement valider le comportement du Client, mais pas le Client lui-même.

Donc, avec SSL, vous pouvez vérifier que le client a un certificat valide ou non, donc on peut simplement installer votre application, obtenir le certificat, puis exécuter tout le nouveau code.

La question est donc: pourquoi est-ce si critique? S'il s'agit d'une préoccupation réelle, je remettrais en question votre choix d'un gros client. Vous devriez peut-être opter pour une application Web (pour ne pas avoir à exposer votre API).

Voir également: Défaite de la validation du certificat SSL pour Android

et: Dans quelle mesure les certificats SSL clients sont-ils sûrs dans une application mobile?

49
Morons

Je suis sûr que vous êtes à l'aise avec les connexions utilisateur et les communications via SSL, donc je vais me concentrer sur ce que je pense que c'est la partie la plus intéressante de la question: comment vous assurer que vos actions en lecture seule - qui pas nécessitent que utilisateur soit authentifié - ne sont acceptés que depuis vos propres applications clientes?

Avant toute chose, il y a l'inconvénient auquel fNek a fait allusion dans une réponse précédente - vos applications clientes sont entre les mains d'utilisateurs potentiellement hostiles. Ils peuvent être examinés, leurs communications inspectées, leur code démonté. Rien de ce que je vais vous suggérer ne vous permettra de garantir que quelqu'un ne procède pas à la rétro-ingénierie de votre client et n'abuse de votre REST API. Mais cela devrait mettre un barrière devant toute tentative fortuite.

Quoi qu'il en soit, une approche commune est la suivante:

  • Le client contient un secret
  • Lors d'une demande, il concatène les paramètres de la demande avec les secrets et hache le résultat
  • Ce hachage est envoyé avec la demande et vérifié par le serveur

par exemple, imaginez une demande de GET pour /products/widgets

Disons que le secret client est "OH_HAI_I_IZ_SECRET"

Concatène le verbe HTTP, l'URL et le secret:

GET/products/widgetsOH_HAI_I_IZ_SECRET

Et prenez un SHA-1 hachage de cela:

4156023ce06aff06777bef3ecaf6d7fdb6ca4e02

Envoyez-le ensuite, donc la demande serait pour:

GET /products/widgets?hash=4156023ce06aff06777bef3ecaf6d7fdb6ca4e02

Enfin, pour empêcher quelqu'un de rejouer au moins des requêtes individuelles, prenez également un horodatage et ajoutez-le aux paramètres et au hachage. par exemple. en ce moment, en temps Unix, est 1384987891. Ajoutez cela à la concaténation:

GET/products/widgetsOH_HAI_I_IZ_SECRET1384987891

Hash that:

2774561d4e9eb37994d6d71e4f396b85af6cacd1

Et envoyer:

GET /products/widgets?time=1384987891&hash=2774561d4e9eb37994d6d71e4f396b85af6cacd1

Le serveur vérifiera le hachage et vérifiera également que l'horodatage est à jour (par exemple dans les 5 minutes pour permettre aux horloges de ne pas être parfaitement synchronisées)

Attention! Puisque vous parlez d'applications mobiles, il y a un risque certain que le téléphone de quelqu'un ait son horloge erronée. Ou le fuseau horaire est incorrect. Ou quelque chose. Ajouter du temps au hachage brisera probablement certains utilisateurs légitimes, alors utilisez cette idée avec prudence.

32
Carson63000

Pour toute personne intéressée, le Android vous POUVEZ vérifier que la demande que vous avez reçue a été envoyée depuis votre application.

En bref, lorsque vous téléchargez votre application sur google, vous la signez, avec une clé unique que vous seul connaissez (et google).

Le processus de vérification se déroule (ish) comme ceci:

  1. votre application va sur Google et demande un jeton d'authentification
  2. votre application envoie le jeton en toute sécurité à votre serveur principal
    1. votre serveur principal va à google et vérifie le jeton d'authentification qu'il a obtenu de votre application.
    2. votre serveur principal vérifie ensuite si la clé unique que votre application a signée correspond, sinon cela signifie que ce n'était pas votre application ...

le blog complet qui l'explique et comment l'implémenter peut être trouvé ici: http://Android-developers.blogspot.co.il/2013/01/verifying-back-end-calls-from-Android.html

17
ndori

Comme @Morons l'a mentionné dans sa réponse, il est très difficile de vérifier l'entité à l'autre extrémité de la connexion.

Le moyen le plus simple de fournir un certain niveau d'authenticité est de demander au serveur de vérifier un secret que seule l'entité réelle connaîtrait. Pour un utilisateur, cela peut être un nom d'utilisateur et un mot de passe. Pour un logiciel sans utilisateur, vous pouvez intégrer un secret.

Le problème avec ces approches est que vous devez faire confiance au client. Si quelqu'un inverse l'ingénierie de votre application ou vole votre mot de passe, il peut prétendre être vous.

Vous pouvez prendre des mesures pour rendre plus difficile l'extraction des informations secrètes en les obscurcissant dans l'exécutable. Des outils comme ProGuard qui est un obscurcisseur pour Java peut aider à cela, je ne sais pas autant sur l'obfuscation dans d'autres langues mais il existe probablement des outils similaires. L'utilisation d'une connexion TLS aide à empêcher les gens espionner votre trafic, mais n'empêche pas une attaque MITM Pinning peut aider à résoudre ce problème.

Je travaille pour une entreprise appelée CriticalBlue (divulgation complète!) Qui a un produit appelé Approov qui essaie de résoudre ce problème de confiance. Il fonctionne actuellement pour Android/iOS et fournit un mécanisme permettant à nos serveurs de vérifier l'intégrité de l'application cliente. Pour ce faire, il demande au client de calculer une réponse à un défi aléatoire. Le client doit calculer la réponse en utilisant des attributs du package d'application installé qui sont difficiles à simuler et il comprend des mécanismes anti-sabotage sophistiqués.

Il renvoie un jeton que vous pouvez ensuite envoyer comme preuve d'authenticité à votre API.

La différence importante avec cette approche est que bien qu'il soit possible de désactiver le contrôle d'authenticité sur le client, si vous le faisiez, vous n'obtiendrez pas le jeton d'authentification dont vous avez besoin pour vérifier votre application auprès du serveur. La bibliothèque est également étroitement liée aux caractéristiques de l'exécutable dans lequel elle se trouve, il serait donc très difficile de l'intégrer dans une fausse application et de la faire fonctionner.

Il existe une analyse coûts/avantages que tout développeur d'API doit effectuer pour décider de la probabilité que quelqu'un essaie de pirater son API et de son coût. Une simple vérification secrète dans l'application empêche les attaques triviales, mais se protéger contre un attaquant plus déterminé est probablement beaucoup plus compliqué et potentiellement coûteux.

5
ThePragmatist

Ok, donc il vaut la peine de mentionner avant de commencer que pour la plupart des applications, c'est extrêmement exagéré. Pour la plupart des cas d'utilisation, le simple fait d'avoir un seul certificat et/ou jeton valide est plus que suffisant. Si cela implique de faire quelque chose de dur comme la décompilation de votre application, même la plupart des pirates ne s'en soucieront pas, sauf si vous fournissez des données très précieuses. Mais bon, où est le plaisir dans cette réponse?

Donc, ce que vous pouvez faire, c'est configurer une cryptographie asymétrique un peu comme signature numérique s utilisée pour signer les programmes. Chaque application peut alors avoir un certificat individuel qui est émis par une seule autorité de certification et vérifié lorsque votre utilisateur se connecte. (soit lors de la première inscription ou lors de la première installation) Lorsque ce certificat est authentifié, vous pouvez ensuite sécuriser davantage votre application en enregistrant ce certificat comme valide pour un identifiant d'appareil donné (tel que ID Android )

5
Tom Squires

SSL sécurisera le canal de communication.

Une connexion réussie émettra un jeton d'authentification sur une connexion cryptée.

Le jeton d'authentification sera transmis à votre REST API dans toutes les demandes suivantes.

1
CodeART

Ce ne serait pas trop sûr, mais vous pourriez ajouter une sorte de code secret ou même une signature numérique. Inconvénient: il doit être inclus dans l'application, ce qui facilite son obtention si vous savez ce que vous faites.

0
fNek

Pour autant que je sache, HTTPS sert uniquement à valider le serveur avec lequel vous communiquez, c'est à dire avec qui il est.

En fait, vous pouvez utiliser SSL pour authentifier le client et le serveur. Ou, autrement dit, "oui, vous pouvez utiliser des certificats clients".

Vous devrez ...

  • regardez la bibliothèque SSL que vous utilisez pour déterminer comment spécifier les certificats clients dans l'appareil mobile,
  • écrire du code ou configurer votre serveur HTTPS pour qu'il n'accepte que les connexions de clients enregistrés et approuvés.
  • trouver un mécanisme pour ajouter des certificats clients de confiance à votre serveur
  • trouver un mécanisme pour supprimer les certificats clients qui ne sont plus fiables de votre serveur

Vous pouvez demander à l'application mobile de stocker le certificat où vous le souhaitez. Étant donné que vous souhaitez l'authentification spécifique à l'application, vous devez envisager de stocker le certificat dans un emplacement de disque protégé (sur Android, vous pouvez créer une table "config" dans votre base de données SQLite, et une ligne pour votre certificat et une autre pour votre clé privée) .

0
atk