web-dev-qa-db-fra.com

Usurpation de requêtes POST / GET dans un service RESTful

J'ai commencé à travailler sur une application qui se connecte à un service RESTful pour l'authentification et les données. User POSTs le nom d'utilisateur et le mot de passe du point de terminaison/token. Une fois qu'ils se sont connectés avec succès, ils obtiennent un jeton de support qu'ils ajoutent ensuite à l'en-tête d'autorisation dans les appels suivants à différentes ressources protégées.

Ma question est de savoir ce qui empêche les utilisateurs d'intercepter leur publication habituelle depuis l'application (obtenir le jeton), puis d'envoyer éventuellement un tas de demandes POST (en utilisant quelque chose comme facteur ou violoneux) pour créer un grand nombre de faux articles ou articles ou quoi que ce soit d'autre que l'application fait.

Quels sont les moyens possibles de se protéger contre cela? Le fait que le trafic vers le service passe finalement par TLS en fait-il un problème?

13
ska-dev

Ma question est de savoir ce qui empêche les utilisateurs d'intercepter leur poste habituel depuis l'application (obtenir le jeton) et ensuite d'envoyer éventuellement un tas de demandes POST (en utilisant quelque chose comme facteur ou violoneux) pour créer un grand nombre de faux articles ou articles ou quoi que ce soit d'autre que l'application fait.

Rien

Le fait que le trafic vers le service passe finalement par TLS en fait-il un problème?

Cela ne fait aucune différence.

Quels sont les moyens possibles de se protéger contre cela?

La plus courante est la limitation de débit. C'est à dire. si quelqu'un poste à un niveau beaucoup plus élevé que prévu, rejetez le message. Il y a plusieurs approches à cela - quand ont-ils posté pour la dernière fois, la moyenne mobile sur N minutes, etc.

Les captchas sont une autre approche. C'est-à-dire essayer de faire prouver à l'utilisateur qu'il est humain.

Un autre tente de détecter le contenu généré automatiquement à l'aide de filtres anti-spam ou de l'IA.

29
Hector

Ma question est de savoir ce qui empêche les utilisateurs d'intercepter leur publication régulière depuis l'application

Rien.

Le fait que le trafic vers le service passe finalement par TLS en fait-il un problème?

Si vous le faites pour une plate-forme mobile (Android/iOS), cela rend beaucoup plus difficile (mais pas impossible).

Si vous le faites pour le navigateur, cela n'ajoute pas beaucoup de protection.

Quels sont les moyens possibles de se protéger contre cela?

Il est difficile de se protéger contre les demandes automatiques, mais une chose que vous pourriez faire est la limite de taux.

12
Ruben_NL

Ma question est de savoir ce qui empêche les utilisateurs d'intercepter leur publication habituelle depuis l'application (obtenir le jeton), puis d'envoyer éventuellement un tas de demandes POST (en utilisant quelque chose comme facteur ou violoneux) pour créer un grand nombre de faux articles ou articles ou quoi que ce soit d'autre que l'application fait.

Quels sont les moyens possibles de se protéger contre cela?

Non. Autrement dit, vous ne vous protégez pas contre ceci - du point de vue de l'authentification et de l'autorisation, aucune attaque ne se produit ici, juste un trafic parfaitement légitime.

Le problème est plutôt "Comment empêcher les utilisateurs de spammer mon service?" (ou similaire), et c'est complètement orthogonal à la question des jetons d'authentification. Un utilisateur peut également spammer des choses manuellement via l'application.

La limitation du débit par compte utilisateur, la limitation du débit par adresse IP, l'utilisation de cookies ou d'identifiants d'appareil pour lier plusieurs comptes ensemble à la limite de débit par appareil, les termes des listes noires, l'heuristique du spam, etc. sont toutes des méthodes courantes pour lutter contre le spam. Mais quelle que soit votre réelle chose, c'est ce que vous essayez d'empêcher, c'est ce que vous devriez examiner, sans empêcher les utilisateurs de modifier les choses côté client (ce qu'ils pourront toujours faire).

Le jeton que vous donnez au client doit contenir une heure d'expiration signée qui serait vérifiée côté serveur (par exemple, limitée à une durée de session utilisateur typique que vous attendez pour votre application). Cela n'empêchera pas la nouvelle publication, mais limitera la période pendant laquelle cela pourrait être fait après l'authentification. À l'expiration, l'utilisateur devra se réauthentifier. Ceci est généralement implémenté en utilisant JSON Web Token .

Cependant, vous parlez d'une mauvaise utilisation malveillante par un utilisateur légitime (sauf si un attaquant a déjà compromis l'appareil de l'utilisateur légitime et peut intercepter le trafic en clair) - une telle mauvaise utilisation est très difficile à empêcher sans rendre l'application presque inutilisable car d'autres ont noté (par exemple, en faisant authentifier les utilisateurs à chaque demande). Stocker les informations d'identification sur l'appareil et les renvoyer silencieusement est un GRAND NON-NON.

4
Sasha K

Il est vrai qu'un jeton de session seul ne garantit pas qu'un pirate ne peut pas intercepter un paquet et réutiliser le jeton à ses propres fins ... au moins tant que le jeton est valide. La plupart des jetons de session ont une limite de temps, bien que cela dépende de la méthode d'autorisation utilisée pour valider le jeton côté serveur.

Le timing est un moyen de se prémunir contre cela, bien qu'il ne soit pas infaillible. Puisque vous écrivez l'application, vous devez avoir une idée raisonnable de la rapidité avec laquelle l'application peut être utilisée et du taux attendu d'appels de service. Si votre application, en utilisation standard, ne peut pas envoyer un appel de service plus d'une fois par seconde, et que le service reçoit 100 demandes en une seconde, c'est clairement un pirate au travail.

Cependant, cela suppose qu'un pirate informatique bombardera votre service de demandes. Un pirate pourrait comprendre cela après quelques échecs et réduire son taux de demandes. Dès qu'ils verront le service rejeter ce qu'ils croient être un jeton de session valide, ils commenceront à regarder l'évidence, comme le timing.

Une autre façon de se prémunir contre cela est d'exiger SSL pour accéder au service. Cela rendra les paquets et le jeton d'autorisation difficiles à extraire. Ils auront besoin de bien plus qu'un renifleur de paquets. Un pirate particulièrement averti pourrait essayer de sonder le binaire de l'application, mais cela demande beaucoup de travail, en particulier sur les plates-formes mobiles. Vous devez acheter un certificat SSL pour le serveur, mais c'est une assurance bon marché.

Une méthode que j'ai expérimentée consiste à ajouter un numéro de séquence au jeton de session, haché afin qu'il ne ressemble pas à un numéro de séquence. Le service d'autorisation conserve un décompte qui est incrémenté chaque fois qu'un jeton est validé. Il supprime les octets de séquence avant de valider le jeton, puis vérifie le numéro de séquence.

Le client doit démarrer à zéro lors de la réception initiale du jeton de session et incrémenter le nombre ajouté de un à chaque appel. Ainsi, lorsque le serveur a reçu la dernière séquence 250, et qu'une autre arrive dans la séquence 135 ... ignorez la demande, verrouillez peut-être l'adresse IP source et envoyez aux administrateurs un avis qu'une tentative de piratage peut être en cours.

Cependant, cela ajoute une certaine complexité à l'application cliente et pourrait également être à l'origine de paquets perdus ou de paquets de retour supprimés. Juste quelque chose que j'ai expérimenté.

Et, oui, un pirate pourrait éventuellement comprendre cela, mais seulement après de nombreux faux départs ... avertissant les administrateurs qu'une tentative d'intrusion est en cours.

2
tj1000

Beaucoup d'autres personnes ont dit "rien" en réponse à la première question sur "ce qui empêche .." et c'est vrai; en fin de compte, rien ne vainc vraiment quelqu'un de absolument déterminé.

Vous avez également demandé des stratégies pour contrer cela; tj1000 en a parlé et j'ai pensé que je lancerais une idée similaire dans la mêlée, basée sur le travail que j'avais l'habitude de faire avec les terminaux de cartes de crédit.

Il y a très longtemps, quand j'étais développeur junior, on m'a confié une tâche jugée trop difficile à résoudre par les développeurs professionnels (je suppose que cela montre un peu ce que j'ai été payé); nous avions des milliers de terminaux de cartes de crédit qui ont appelé via une ancienne liaison pré-isdn, ont fait une authentification, ont enregistré une transaction, ont obtenu une approbation ou un refus du serveur et à la prochaine transaction. La partie mignonne est qu'il n'y a jamais eu d'autre suivi de message du terminal si la transaction a été annulée après l'avoir approuvée (c'était à l'époque des signatures, avant que l'identité de l'utilisateur ne soit préautorisée par une puce et une épingle), mais il n'y en a pas eu pas besoin d'être

Ces transactions ont été protégées et confirmées par ce qu'on a appelé un code d'authentification de message MAC. Une clé de hachage, unique par terminal, a été intégrée au matériel du terminal par le fabricant. Le fabricant partagerait avec nous ce qu'était la clé de hachage, et lorsque le terminal est apparu présentant son ID non valide, nous pourrions rechercher la clé de hachage. Les octets de message que le terminal formé serait hachés par le terminal, la moitié du hachage précédent ou initial étant ajoutée au message. L'autre moitié serait utilisée pour mettre à jour la clé de hachage utilisée pour le prochain message. Côté serveur, nous effectuions le même hachage pour savoir si le message avait été falsifié, et arrivions au même résultat de hachage, nous saurions également faire rouler la clé de hachage avec le même demi-résidu que nous avions, mais nous garderions également la trace du hachage précédent. La prochaine fois qu'un message est entré, l'une des deux choses a été le cas. Si la transaction précédente avait réussi et devait être cumulée dans les totaux quotidiens, le terminal utiliserait sa nouvelle clé de hachage roulée pour hacher le dernier message. Si la transaction précédente était annulée (utilisateur annulé, mauvaise signature, etc.), le terminal réutiliserait la clé de hachage précédente. En hachant le message avec la dernière clé roulée et en ne trouvant aucune correspondance, mais en hachant avec la clé précédente et en trouvant une correspondance, nous savions que le sort de la transaction précédente avait échoué, et nous le supprimerions des totaux quotidiens.

Les clés de hachage se désynchronisaient parfois; lorsque cela se produisait, aucune de nos clés stockées ne produirait un hachage correspondant pour le message. Il y a une clé de plus à essayer - la clé initiale (les utilisateurs superviseurs pouvaient réinitialiser la clé à l'initiale, et certains utilisateurs semblaient le faire en cas de problème, pensant que c'était quelque chose comme un redémarrage - rarement le cas et causait plus de problèmes qu'il ne le faisait résolu mais ..). Si la clé initiale fonctionnait, nous ne pouvions pas dire avec certitude ce qui était arrivé à la transaction précédente, mais nous les accumulions généralement (comptes de personnes facturés) sur la base de la théorie selon laquelle les gens se plaindraient s'ils n'étaient pas remboursés à l'échéance, mais pas s'ils ont été remboursés quelque chose qu'ils avaient acheté ..

si la clé initiale n'a pas fonctionné, alors le terminal est devenu inutile, car la perte de synchronisation de la clé signifie qu'aucun autre message ne peut fonctionner. Nous n'avions pas le pouvoir de dire au terminal de réinitialiser lui-même sa clé, mais nous pourrions afficher un message implorant l'utilisateur de le faire

Pour faire court, vous n'avez pas à utiliser le même jeton, si vous craignez que les jetons soient capturés et rejoués en tant qu'alternative de mot de passe stockée. D'autres ont souligné des options pour faire expirer les jetons après un certain temps; cette méthode est essentiellement l'expiration du jeton après chaque demande (similaire à une autre mention concernant l'ajout d'un numéro séquentiel à un jeton), avec une manière interne connue de calculer un nouveau jeton de chaque côté qui doit être effectué à l'étape.

Si vous êtes intéressé par les détails ennuyeux de la façon dont le monde des cartes de crédit le fait au Royaume-Uni, consultez APACS 70 Standard Book 2 et Book 5. Ceux-ci ne sont pas disponibles gratuitement, hélas - vous devez être membre pour recevoir une copie de nouvelles publications, mais vous pourriez trouver le contenu de leurs anciennes versions flottant sur le Web

1
Caius Jard

Donc ... il n'y a rien que vous puissiez faire pour sécuriser la machine cliente afin de sécuriser le jeton de son côté, mais il existe quelques bonnes pratiques en matière de sécurité JWT:

  1. Implémentez des jetons de rafraîchissement et émettez des jetons d'accès de courte durée - cela ajoute de la complexité à toute attaque + la façon dont j'ai vu le jeton de rafraîchissement implémenté est avec une table SQL ... que vous pouvez gérer (ex. Démarrage instantané).

  2. Supprimez le jeton du client lors de la déconnexion (celui-ci est évident).

  3. Vous pouvez chiffrer le jeton, mais le chiffrement réversible le rend encore plus difficile.

  4. Utilisez une clé secrète pour signer vos jetons et faites-la pivoter au besoin (par ex. Par version). La modification de la clé secrète invalide tous les jetons antérieurs.

Lisez également: https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/

Si vous avez besoin de plus de sécurité, vous avez besoin de plus de mécanismes pour sécuriser spécifiquement le client: liste blanche des IP des utilisateurs, assurer aux utilisateurs une formation AV et anti-phishing, etc.

1
RandomUs1r

TL; DR un utilisateur qualifié satisfait d'un taux de spam raisonnable passera toujours - si ce n'est par aucun autre moyen, en saisissant son spam à la main .


Demandez à l'application d'authentifier chaque demande indépendamment. Ce n'est certainement pas infaillible, et cela augmente le trafic, mais c'est faisable.

Une façon: un message n'est plus un seul message mais un GET suivi du POST. Le GET fournit un nonce (il pourrait s'agir de l'horodatage actuel) et le POST doit fournir le nonce avec par exemple le MD5 du nonce, salé avec un secret d'application. Bien sûr, vous devez stocker les nonces émis pour éviter les attaques de rejeu.

Vous pouvez également fournir un nonce de session lors de la connexion et l'utiliser pour toute la session (bien sûr, l'utilisateur peut l'intercepter et le copier dans une deuxième application de spam, une fois qu'il a brisé le secret de l'application de l'application). Ce n'est cependant pas une amélioration significative par rapport au cookie d'authentification.

Ou vous pouvez ajouter silencieusement une validation à toutes les demandes d'application, sous la forme de l'horodatage actuel plus le hachage dudit horodatage salé avec le secret de l'application. L'unicité peut alors être garantie en empêchant deux publications dans le même deuxième côté client.

Le serveur vérifie ensuite que l'horodatage n'est pas trop éloigné de maintenant () et que le hachage correspond. Vous pouvez même omettre l'horodatage s'il est acceptable pour le serveur de le forcer brutalement (pour horodatage = maintenant () - 60 à maintenant () + 60; si hachage (secret + horodatage) ...).

Maintenant, l'utilisateur doit pirater le secret de votre application, ce qui est plus difficile que d'intercepter le trafic réseau. Si les chaînes/données sont facilement reconnaissables dans l'application, vous pouvez ajouter une sécurité pe à travers l'obscurité en envoyant l'horodatage, et le hachage du secret plus l'horodatage de sept secondes avant 1. Cela nécessite que l'utilisateur procède à une ingénierie inverse de l'application.


(1) J'ai une fois rompu un schéma de salage en testant toutes les séquences de 1 à 32 octets dans un programme, apposées et suffixées à l'horodatage en hexadécimal, binaire et décimal, avec un ensemble de séparateurs, y compris le non-séparateur, et en vérifiant si le résultat était le réponse au défi. Cela m'a permis de ne pas déboguer le binaire du tout, ce que je n'aurais pas pu faire, et cela a pris vingt minutes à configurer, et deux à courir. Si l'horodatage avait été masqué par l'ajout d'une constante connue, je n'aurais pas réussi. Si la constante était grande, ce ne serait pas pratique, même en connaissant l'astuce.

1
LSerni

Comme d'autres l'ont abordé, il n'y a pratiquement rien que vous puissiez faire une fois que le code est exécuté sur l'appareil d'un utilisateur. S'il s'exécute dans le navigateur, la rétro-ingénierie du processus de jeton est triviale. S'il fonctionne dans une application, vous pouvez rendre la rétro-ingénierie beaucoup plus difficile, mais c'est toujours possible.

Pour les applications mobiles, l'attaquant a deux options:

1) Rétro-ingénierie du protocole. L'approche la plus simple consiste à renifler le trafic réseau. Il y a des obfuscations que vous pouvez mettre en place pour rendre cela plus difficile (épinglage de certificats, MAC + clé secrète + rotation) mais tout attaquant déterminé finira par les percer. Cependant, si vous utilisez l'épinglage de certificats et/ou l'approche par clé secrète, l'attaquant ne pourra pas simplement renifler les paquets pour effectuer une rétro-ingénierie du protocole. Il devra décompiler le binaire afin de désactiver l'épinglage de certificats et/ou de localiser la clé secrète en mémoire.

2) Traitez l'application comme une boîte noire et automatisez l'interaction avec elle. Cela pourrait être fait avec une batterie de périphériques physiques (beaucoup plus facile si iOS jailbreaké/rooté Android), ou avec une ferme d'émulateurs. Du point de vue d'un attaquant, cela pourrait être une approche plus fiable car elle résiste à toutes les mises à jour que vous envoyez.

Pour vous prémunir contre # 1 (décompilation binaire), vous avez de nombreuses options, mais elles se résument toutes à augmenter la difficulté de la rétro-ingénierie, sans l'empêcher complètement. Le fruit bas est l'obscurcissement binaire et la détection du débogueur. Pour l'obscurcissement, vous pouvez obscurcir les tables de symboles et/ou masquer la logique de chiffrement dans des fonctions d'apparence banale (ou l'écrire directement dans Assembly). Pour la détection du débogueur, il existe différentes techniques pour déterminer si un débogueur est en cours d'exécution; si vous en attrapez un, vous pouvez planter l'application ou jouer à des jeux avec l'attaquant.

La protection contre # 2 (batterie d'émulateurs/d'appareils) est un peu plus difficile, mais encore une fois, vous pouvez rendre le travail de l'attaquant plus difficile. Une option consiste à vérifier si l'appareil est jailbreaké (cela se défendrait également contre # 1) et à planter l'application si c'est le cas. Une autre option, pour Android au moins, est Google service d'attestation . Cela devrait empêcher le scénario de la ferme d'émulation, mais pas une ferme physique. Pour iOS, Apple a publié une version similaire deviceCheck API dans iOS11, bien que sa portée soit beaucoup plus limitée.

Si vous voulez des exemples de cela dans la nature, consultez Snapchat.app, qui a mis en œuvre plusieurs de ces fonctionnalités.

1
formicophobia

Si une application est conçue pour s'authentifier (nom d'utilisateur/mot de passe) une fois, puis utiliser un système de jetons pour l'autorisation de services REST), cette application a effectivement créé son propre accès par porte dérobée.

Je suis sûr que cette solution va me faire fouetter, mais vous devez essentiellement vous authentifier dans chaque point de terminaison RESTful unique.

Vous pouvez choisir de harceler vos utilisateurs et demander un mot de passe à chaque demande REST mais cela pourrait rendre votre application susceptible de devenir un échec.

L'autre option consiste à stocker les informations d'identification de l'utilisateur dans la mémoire de l'application lors de la connexion et à envoyer les informations d'identification en mode silencieux aux points de terminaison REST.

0
MonkeyZeus