Est-il facile de pirater JavaScript (dans un navigateur)?

37

Ma question concerne la sécurité JavaScript.

Imaginez un système d'authentification utilisant un framework JavaScript tel que Backbone ou AngularJS , et vous avez besoin de points de terminaison sécurisés. Ce n'est pas un problème, car le serveur a toujours le dernier mot et vérifiera si vous êtes autorisé à faire ce que vous voulez.

Mais que faire si vous avez besoin d’un peu de sécurité sans impliquer le serveur? Est-ce possible?

Par exemple, supposons que vous disposiez d'un système de routage côté client et que vous souhaitiez protéger un itinéraire concret pour les utilisateurs connectés. Donc, vous envoyez une requête ping au serveur vous demandant si vous êtes autorisé à visiter des itinéraires protégés et vous poursuivez. Le problème est que lorsque vous envoyez une requête ping au serveur, vous stockez la réponse dans une variable. Ainsi, lors de votre prochain passage sur une route privée, il vérifiera que, si vous êtes déjà connecté (pas de ping vers le serveur), sur la réponse cela ira ou pas.

Est-il facile pour un utilisateur de modifier cette variable et d'obtenir un accès?

Mes connaissances en sécurité (et JavaScript) ne sont pas excellentes. Mais si une variable n’a pas une portée globale et se trouve dans la partie privée d’un modèle de module qui n’a que des accesseurs, mais pas des setters, même dans ce cas, pouvez-vous pirater la chose?

Jesus Rodriguez
la source
29
Toutes ces longues réponses. En bref, pour vous répondre en-tête, "très piratable". Pour répondre à vos deux premières questions, "sans serveur, vous avez perdu la sécurité" && "Non". Pour répondre à la troisième question, "Très facile", et enfin "Oui, facilement". Voilà. Toutes les questions ont répondu. : P
SpYk3HH
Premier exemple, voir mon article sur l’ajout de jQuery à n’importe quelle page Web. spyk3lc.blogspot.com/2013/05/… Maintenant, jeune padawan, allez de l'avant et essayez-le. Voyez à quel point il est facile d’ajouter jQuery à n’importe quel site qui ne l’a pas déjà, puis utilisez jQuery pour manipuler très facilement n’importe quelle partie de la vue sans longues lignes de javascript. Boom!
SpYk3HH
7
Une fois, lors de l’enregistrement d’un nom de domaine, le numéro de téléphone était un champ obligatoire, mais celui-ci n’était appliqué que dans javascript - pas dans le côté serveur. Alors, je l’ai désactivé en redéfinissant une fonction (en utilisant Firebug), et le tour est joué! Ils n'ont pas mon numéro de téléphone.
Izkata
8
manipulate any part of the sight without long lines site vs sight
mplungjan
8
Les programmeurs Web professionnels ont besoin de bien faire les choses. S'il vous plaît. C'est plus embarrassant qu'un truc nazi de grammaire :) plus.google.com/u/0/+MonaNomura/posts/h9ywDhfEYxT
mplungjan le

Réponses:

26

Veuillez lire la réponse de Joachim avant de lire celle-ci. Il couvre les raisons générales de la vulnérabilité côté client. Maintenant, pour une suggestion, comment vous pourriez résoudre ce problème ...

Un schéma sécurisé pour la communication client-serveur sans devoir s’authentifier manuellement auprès du serveur à chaque requête:

Vous laissez toujours le serveur avoir le dernier mot et le serveur doit toujours valider tout ce que dit le client, mais cela se fait de manière transparente.

Supposons que le protocole HTTPS empêche les attaques par interception (MITMA).

  • Le client dialogue pour la première fois avec le serveur. Le serveur génère une clé publique pour le client et conserve une clé privée à l'aide d'un schéma de chiffrement asymétrique. Le client stocke la clé "publique" du serveur dans la mémoire de stockage locale, chiffrée avec un mot de passe sécurisé que vous n'enregistrez nulle part.

  • Le client est maintenant hors ligne. Le client veut effectuer des actions approuvées. Le client entre son mot de passe et saisit la clé publique du serveur.

  • Le client effectue maintenant des actions en fonction de sa connaissance de ces données et le client chiffre chaque action qu'il effectue avec la clé publique du serveur pour ce client .

  • Lorsque le client est en ligne, le client envoie son ID client et toutes les actions effectuées par le client sont envoyées au serveur cryptées avec la clé publique du serveur.

  • Le serveur décrypte les actions et si leur format est correct, il est convaincu qu'elles ont été créées par le client.

Remarque:

  • Vous ne pouvez pas stocker le mot de passe du client n'importe où, sinon un attaquant pourrait récupérer la clé et signer les actions comme siennes. La sécurité de ce schéma repose uniquement sur l'intégrité de la clé générée par le serveur pour le client. Le client doit toujours être authentifié auprès du serveur pour demander cette clé.

  • En fait, vous comptez toujours sur le serveur pour la sécurité et non sur le client. Chaque action effectuée par le client doit être validée sur le serveur.

  • Il est possible d'exécuter des scripts externes dans des travailleurs Web . Gardez à l'esprit que chaque demande JSONP que vous avez est maintenant un problème de sécurité beaucoup plus important. Vous devez protéger la clé à tout prix. Une fois que vous l'avez perdu, un attaquant peut usurper l'identité de l'utilisateur.

  • Cela répond à votre demande selon laquelle «aucun ping vers le serveur» n'est effectué. Un attaquant ne peut pas simplement imiter une requête HTTP contenant des données falsifiées s’il ne connaît pas la clé.

  • La réponse de Joachim est toujours correcte . En fait, vous effectuez toujours toute l’authentification sur le serveur . La seule chose que vous avez enregistrée ici est la nécessité de valider le mot de passe avec le serveur à chaque fois. Vous devez maintenant uniquement impliquer le serveur lorsque vous souhaitez valider ou extraire des données mises à jour. Tout ce que nous avons fait ici est de sauvegarder une clé approuvée côté client et de le valider à nouveau.

  • C'est un schéma assez courant pour les applications à une seule page (par exemple, avec AngularJS).

  • J'appelle la clé publique du serveur "public" à cause de ce que cela signifie dans des schémas comme RSA , mais il s'agit en fait d'informations sensibles dans le schéma et doit être sauvegardé.

  • Je ne garderais le mot de passe nulle part en mémoire. Je ferais en sorte que l'utilisateur envoie son mot de passe "hors connexion" chaque fois qu'il commence à exécuter du code hors connexion.

  • Ne lancez pas votre propre cryptographie - utilisez une bibliothèque connue comme celle de Stanford pour l'authentification.

  • Suivez ce conseil tel quel . Avant de lancer ce type d'authentification dans une application critique du monde réel, consultez un expert en sécurité . Il s’agit d’un problème grave, à la fois douloureux et facile à se tromper.

Il est essentiel qu'aucun autre script n'ait accès à la page. Cela signifie que vous n'autorisez que les scripts externes avec des travailleurs Web. Vous ne pouvez faire confiance à aucun autre script externe susceptible d'intercepter votre mot de passe lorsque l'utilisateur le saisit.

Utilisez un champ de mot de passe promptet non un mot de passe en ligne si vous n'êtes pas complètement sûr et que vous ne retardez pas son exécution (autrement dit, il ne devrait pas survivre à un point où les événements y ont accès, mais uniquement en code de synchronisation). Et ne stockez pas réellement le mot de passe dans une variable - encore une fois, cela ne fonctionne que si vous faites en sorte que l'ordinateur de l'utilisateur ne soit pas compromis (bien que ce soit tout aussi vrai pour la validation sur un serveur).

J'aimerais ajouter à nouveau que nous ne faisons toujours pas confiance au client . Vous ne pouvez pas faire confiance au client seul, et je pense que la réponse de Joachim résume tout. Nous avons seulement eu l'avantage de ne pas avoir à envoyer une requête ping au serveur avant de commencer à travailler.

Matériel connexe:

Benjamin Gruenbaum
la source
3
"Ne lancez pas votre propre crypto" s'applique autant aux protocoles qu'aux primitives, sinon plus, car si les gens ne sont généralement pas assez sots pour créer leurs propres primitives, ils pensent pouvoir créer un protocole qui convient . Je ne vois pas non plus pourquoi la RSA est nécessaire ici. Puisque vous utilisez HTTPS, pourquoi ne pas simplement générer un secret partagé de 16 à 32 octets et exiger qu'il soit envoyé avec les demandes futures? Bien sûr, si vous faites cela, veillez à utiliser une vérification d'égalité invariante dans le temps sur la chaîne ...
Reid
2
+1 @Reid Ouais, je viens de discuter de cela avec un expert récemment. J'ai basé approximativement le schéma primitif ici sur un protocole que j'ai appris (par Rabin IIRC) mais au moins jusqu'à ce que je puisse trouver les détails (et justifier par exemple pourquoi le cryptage asymétrique est nécessaire dans ce cas). N'utilisez pas le schéma suggéré dans cette réponse sans consulter au préalable un expert en sécurité . J'ai vu cette approche utilisée à plusieurs endroits, mais dans la pratique, cela signifie très peu, voire pas du tout. J'ai également édité la réponse pour améliorer cela.
Benjamin Gruenbaum
L'utilisation d'une invite ajoute peu de sécurité. Un attaquant peut écraser la window.promptméthode afin d'intercepter la phrase secrète, ou lancer sa propre invite (éventuellement au sein d'un iframe!). Un champ de mot de passe présente un avantage supplémentaire: les caractères ne sont pas affichés.
Rob W
@RobW Bien sûr, tout ce schéma ne sert à rien si la page était compromise. Si l'attaquant a accès à l'exécution de JavaScript dans la page, nous sommes vissés. L'idée derrière prompt était que cela bloquait, mais vous avez raison, aucun avantage en termes de sécurité n'est douteux. Voir le dernier lien de la liste.
Benjamin Gruenbaum
1
Tout d'abord. Réponse géniale, je pense que je ne peux rien demander d’autre. D'autre part, je voulais faire des projets pour animaux de compagnie pour moi (et bien sûr pour qui veut l'utiliser) et c'est peut-être exagéré (ou peut-être pas). Je veux dire, je ne veux rien faire de grave et j'ai bien peur de ne pas pouvoir avoir ce genre d'autorité que vous avez expliqué, le manque de connaissances. Je pense que je lancerais un simple contrôle 401 ou, si je n’ai aucune demande, j’envoie une requête ping au serveur chaque fois que j’accède à ce type de route. Le jeton d’authentification est également une option (et peut-être le plus proche de ce que vous avez expliqué ici, autant que je sache). Merci vous :)
Jesus Rodriguez
89

C'est simple: tout mécanisme de sécurité reposant sur le client qui ne fait que ce que vous lui dites de faire peut être compromis lorsqu'un attaquant contrôle le client.

Vous pouvez effectuer des vérifications de sécurité sur le client, mais uniquement pour agir efficacement en tant que "cache" (afin d'éviter d'effectuer un aller-retour coûteux vers le serveur si le client sait déjà que la réponse sera "non").

Si vous souhaitez conserver les informations d'un ensemble d'utilisateurs, assurez-vous que le client de ces utilisateurs ne parvient jamais à ces informations. Si vous envoyez ces "données secrètes" avec des instructions "mais ne les affichez pas," il deviendra trivial de désactiver le code qui vérifie cette demande.

Comme vous le voyez, cette réponse ne mentionne pas vraiment les spécificités de JavaScript / Navigateur. C'est parce que ce concept est le même, peu importe ce que votre client est. Peu importe qu'il s'agisse d'un client lourd (application client / serveur traditionnelle), d'une application Web de la vieille école ou d'une application d'une seule page avec JavaScript étendu côté client.

Une fois que vos données ont quitté le serveur, vous devez supposer qu'un attaquant en a un accès total.

Joachim Sauer
la source
Merci. Ce serait bien si vous pouviez l'expliquer un peu plus, mes connaissances en sécurité ne sont pas très bonnes et la seule partie que je comprends est que je me trompe: P. Lorsque vous parlez de mise en cache, vous ne devez mettre en cache que lorsque le serveur dit non? Je veux dire, si le serveur a dit oui une fois, vous ne pouvez pas le mettre en cache, non?
Jesus Rodriguez
3
Je voudrais juste ajouter qu'il est possible d'accéder aux variables de fermeture dans le navigateur (comme dans le modèle de module que vous avez mentionné), en particulier avec un débogueur :)
Benjamin Gruenbaum
2
@BenjaminGruenbaum: n'hésitez pas à développer cela en une réponse centrée sur le côté JS. Je n'ai donné ici que la vue d'ensemble de haut niveau, indépendante de la technologie. Une réponse axée sur JS elle-même serait également bien!
Joachim Sauer
1
En bref, si certaines informations / routes / tout ce qui est accessible en fonction d'une variable javascript, cela ne sera pas sûr dans tous les cas, car vous pouvez facilement changer cette variable pour indiquer ce dont vous avez besoin pour accéder à ces informations privées.
Jesus Rodriguez
4
@ JoachimSauer Je pense que cela passerait à côté de la question que vous avez bien posée. Quelles que soient les mesures de sécurité prises par le client, il est possible de compromettre la communication . Vous pouvez créer des systèmes d’authentification très solides en JavaScript, mais cela n’a aucune valeur dès que vous insérez une communication avec un serveur que d’autres clients considèrent également comme une source de vérité. Le code source est entièrement envoyé au client, un attaquant intelligent peut simplement le lire et imiter une requête HTTP vers le serveur. Il faut traiter tout ce qui provient du client comme non approuvé, sauf s'il est validé sur le serveur.
Benjamin Gruenbaum
10

Il y a un dicton dans la communauté de jeu: " Le client est entre les mains de l'ennemi". Tout code exécuté en dehors d'une zone sécurisée, telle que le serveur, est vulnérable. Dans le scénario le plus élémentaire, vulnérable au risque de ne pas être exécuté en premier lieu. C'est le client qui décide d'exécuter votre" code de sécurité "et l'utilisateur peut "opt-out". Bien qu'avec le code natif, vous ayez au moins une obfuscation automatique dans l'assembly et une couche de protection supplémentaire du fait qu'un attaquant doit être un bon programmeur pour manipuler cela, JS est normalement sans obfucated et en texte brut. Pour lancer une attaque, il suffit de disposer d'outils primitifs, tels qu'un serveur proxy et un éditeur de texte, mais il faudra encore un certain niveau d'instruction en programmation, mais il est beaucoup plus simple de modifier un script à l'aide d'un éditeur de texte que d'injecter du code dans un exécutable.

nvoigt
la source
L'assemblée n'est pas un obscurcissement, et qui croit que autrement n'a jamais joué à un jeu de
guerre
@miniBill: Bien qu'un attaquant moyennement expérimenté n'aura aucun problème avec le code assemblé, il fournirait un filtre passe-haut très basique. (Hélas, c'est académique, car éliminer les scripts pour enfants offre une sécurité minimale pour le scénario du PO)
Piskvor
1

Ce n'est pas une question de piratage JavaScript. Si je voulais attaquer votre application, j'utiliserais un proxy privé qui me permettrait de capturer, de modifier et de rejouer le trafic. Le système de sécurité que vous proposez ne semble pas avoir mis en place de protection.

Mark E. Haase
la source
0

En ce qui concerne spécifiquement Angular:

La protection d'un itinéraire côté client n'existe tout simplement pas. Même si vous "cachez" un bouton sur cette route, l'utilisateur peut toujours le saisir, Angular se plaindra, mais le client pourra y coder.

À un moment donné, votre contrôleur va devoir demander au serveur les données nécessaires au rendu de la vue. Si l'utilisateur n'est pas autorisé à accéder à ces données, il ne les recevra pas car vous avez protégé ces données côté serveur. et votre application Angular doit gérer le 401 de manière appropriée.

Si vous essayez de protéger les données brutes, vous ne pouvez pas utiliser le côté client. Si vous voulez seulement qu'un utilisateur particulier puisse uniquement visualiser les données communes d'une certaine manière, créez les "vues" des données sur le serveur plutôt que les envoyer. données brutes au client et de les réorganiser (vous devriez de toute façon déjà le faire pour des raisons de performances).

Note latérale: les modèles de vue que Angular demande ne doivent en aucun cas être sensibles, mais ne le faites pas. Si c'est le cas, vous devez protéger ces modèles de vue côté serveur, comme vous le feriez si vous effectuiez un rendu côté serveur.

marque
la source