web-dev-qa-db-fra.com

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

Ma question concerne la sécurité JavaScript.

Imaginez un système d'authentification où vous utilisez un framework JavaScript comme 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. Vous envoyez donc une requête ping au serveur pour savoir si vous êtes autorisé à visiter les itinéraires protégés et vous continuez. Le problème est que lorsque vous envoyez une requête ping au serveur, vous stockez la réponse dans une variable, donc la prochaine fois que vous irez sur une route privée, elle vérifiera que si vous êtes déjà connecté (pas de ping au serveur), et selon sur la réponse, il ira ou non.

Est-il facile pour un utilisateur de modifier cette variable et d'y accéder?

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

37
Jesus Rodriguez

Veuillez lire réponse de Joachim avant de lire celui-ci. Il couvre les raisons générales de la vulnérabilité côté client. Maintenant, pour une suggestion sur la façon de contourner ce problème ...

Un schéma sécurisé pour la communication client-serveur sans avoir à s'authentifier manuellement auprès du serveur à chaque demande:

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

Supposons le protocole [[# #]] https [~ # ~] pour empêcher attaques man-in-the-middle (MITMA).

  • Le client établit une poignée de main avec le serveur pour la première fois, et le serveur génère une clé publique pour le client et conserve une clé privée en utilisant un schéma de chiffrement asymétrique. Le client stocke la clé "publique" du serveur dans le stockage local, cryptée avec un mot de passe sécurisé que vous ne sauvegardez nulle part.

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

  • Le client effectue désormais 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échiffre les actions et, si elles sont au format correct, il espère qu'elles proviennent du 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é que le serveur génère pour le client. Le client devra toujours être authentifié auprès du serveur lors de la demande de cette clé.

  • En fait, vous comptez toujours sur le serveur pour la sécurité et pas le client. Chaque action que le client vous effectue doit valider sur le serveur.

  • Il est possible d'exécuter des scripts externes dans web workers . Gardez à l'esprit tous JSONP la demande 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 avec 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. Il vous suffit désormais d'impliquer le serveur lorsque vous souhaitez valider ou d'extraire des données mises à jour. Tout ce que nous avons fait ici est de sauvegarder une clé de confiance côté client et de la faire revalider par le client.

  • Il s'agit d'un schéma assez courant pour les applications d'une seule page (par exemple, avec AngularJS).

  • J'appelle la clé publique du serveur "publique" en raison de ce que cela signifie dans des schémas comme RSA , mais ce sont en fait des informations sensibles dans le schéma et doivent être sauvegardées .

  • Je ne garderais le mot de passe nulle part en mémoire. Je demanderais à l'utilisateur de soumettre son mot de passe "hors ligne" chaque fois qu'il/elle commence à exécuter du code hors ligne.

  • Ne lancez pas votre propre cryptographie - utilisez une bibliothèque connue comme 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 qui est à la fois douloureux et facile à se tromper.

C'est critique qu'aucun autre script n'a accès à la page. Cela signifie que vous autorisez uniquement les scripts externes avec des travailleurs Web. Vous ne pouvez pas faire confiance à d'autres scripts externes qui pourraient intercepter votre mot de passe lorsque l'utilisateur le saisit.

Utilisez un Prompt et pas un champ de mot de passe en ligne si vous n'êtes pas complètement sûr et ne différez pas son exécution (c'est-à-dire qu'il ne devrait pas vivre à 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 pensez que l'ordinateur de l'utilisateur n'est pas compromis (bien que cela soit également vrai pour la validation par rapport à un serveur).

Je voudrais 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 le résume. Nous avons seulement gagné la commodité de ne pas avoir à cingler le serveur avant de commencer à travailler.

Matériel connexe:

26

C'est simple: tout mécanisme de sécurité qui repose sur le client pour faire uniquement ce que vous lui demandez de faire peut être compromis lorsqu'un attaquant a le contrôle sur le client.

Vous pouvez effectuer des contrôles de sécurité sur le client, mais uniquement pour agir efficacement comme un "cache" (pour éviter de faire 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 n'obtient jamais ces informations. Si vous envoyez ces "données secrètes" avec des instructions "mais s'il vous plaît 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 de spécificités JavaScript/navigateur. C'est parce que ce concept est le même, quel que soit votre client. Peu importe qu'il s'agisse d'un gros client (application client/serveur traditionnelle), d'une application Web ancienne école ou d'une application d'une seule page avec un JavaScript côté client étendu.

ne fois que vos données quittent le serveur, vous devez supposer qu'un attaquant y a un accès complet.

89
Joachim Sauer

Il y a un dicton dans la communauté des joueurs: "Le client est entre les mains de l'ennemi". Tout code qui s'exécute en dehors d'une zone sécurisée comme le serveur est vulnérable. Dans le scénario le plus élémentaire, vulnérable à ne pas être exécuté en premier lieu. C'est la décision du client d'exécuter réellement votre "code de sécurité" et l'utilisateur peut simplement "se désinscrire". Alors qu'avec le code natif, vous avez au moins une obfuscation automatique dans Assembly et une couche de protection supplémentaire par le fait qu'un attaquant doit être un bon programmeur pour manipuler cela, JS est normalement non obstrué et en texte brut. Tout ce dont vous avez besoin pour organiser une attaque sont des outils primitifs comme un serveur proxy et un éditeur de texte. L'attaquant aura toujours besoin d'un certain niveau d'éducation concernant la programmation, mais il est beaucoup plus facile de modifier un script en utilisant n'importe quel éditeur de texte que d'injecter du code dans un exécutable.

10
nvoigt

Il ne s'agit pas de pirater JavaScript. Si je voulais attaquer votre application, j'utiliserais un proxy privé qui me permettrait de capturer, de modifier et de rejouer le trafic. Votre système de sécurité proposé ne semble pas avoir de protection en place contre cela.

1
Mark E. Haase

En parlant spécifiquement d'Angular:

La protection d'une route 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 peut coder autour de cela.

À un moment donné, votre contrôleur devra demander à votre serveur les données nécessaires pour afficher 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 correctement le 401.

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

Remarque: il ne devrait jamais y avoir quoi que ce soit de sensible dans les modèles de vue qui Angular demande, ne le faites pas. Si pour une raison folle il y en a, vous devez protéger ces modèles de vue sur le côté serveur, comme vous le feriez si vous faisiez un rendu côté serveur.

0
Mark