web-dev-qa-db-fra.com

Comment sécuriser les demandes de liens Ajax?

Imaginez le scénario suivant: un utilisateur souhaite s'inscrire sur une page Web et remplit un formulaire. Pendant qu'il remplit le formulaire, jQuery continue de vérifier via un expression régulière si les champs sont valides, etc ...

En prenant l'e-mail comme clé primaire que l'utilisateur utilisera après son inscription pour se connecter, le champ e-mail doit être vérifié avec Ajax pour permettre à l'utilisateur de savoir si cet e-mail est enregistré ou non. Je veux le vérifier avec Ajax pour éviter d'envoyer le formulaire complet et de le vider, de rafraîchir la page, etc ...

Ainsi, lorsque l'utilisateur a fini de remplir le champ e-mail, la demande Ajax est envoyée au serveur, quelque chose comme le lien suivant:

example.com/[email protected]

Lorsque check.php reçoit l'e-mail, il demande à la base de données s'il existe ou non et renvoie un message du type: User already exists si l'utilisateur existe ou null si l'utilisateur n'existe pas.

La question est: si quelqu'un fouille dans mon .js et découvre des liens similaires, il pourrait utiliser ce lien pour envoyer un grand nombre de demandes à savoir si ces e-mails aléatoires existent. Cela pourrait entraîner une utilisation intensive de la base de données ou, dans le pire des cas, même des plantages et des fuites d'informations privées.

Quelqu'un pourrait faire une énorme boucle for pour vérifier les e-mails comme:

//Getting the response of the next links
example.com/[email protected] // Returns null
example.com/[email protected] // Returns null
example.com/[email protected] // Returns null
example.com/[email protected] // Returns User already exists

----------------------------------------- -------------------------------------------------- -----------------------------------------

Depuis que j'ai accepté la réponse pour la dernière fois, j'ai continué à enquêter et trouvé la solution pour éviter ce comportement. Le code suivant est pour Java mais la logique peut être appliquée à tout autre langage côté serveur.

Avant de faire N'IMPORTE QUELLE demande ajax au serveur, je demande un jeton au serveur. Ce jeton ressemble à ceci fmf5p81m6e56n4va3nkfu2ns8n il est fait par une méthode simple, il peut cependant être plus complexe, mais c'est bon à faire.

public String getToken() throws UnsupportedEncodingException {
    return new BigInteger(130, new SecureRandom()).toString(32);
}

Lors de la demande du jeton, le serveur ne renvoie pas seulement le jeton, mais aussi un petit script qui, au cas où quelqu'un utiliserait le navigateur pour inspecter l'élément (et la barre de navigation du navigateur), le script s'exécutera et le jeton sera effacé. Servlet renvoie quelque chose comme ceci:

_html += "<head>"
    + "<script> "
    + "window.onload=function(){\n"
    + "       document.body.innerHTML = \"\";\n"
    + "    }"
    + "window.location.href='http://mywebsite.com' "
    + "</script>"
    + "</head>"
    + "<body>"
    + "[" + token+ "]"
    + "</body>"
    + "</html>";

Vide d'abord le corps, puis retourne là où nous voulons. javascript/jquery capturera cependant tout le contenu sous forme de chaîne, puis j'extrais simplement la chaîne entre [et]. Ce jeton n'est disponible que pour la prochaine demande, donc chaque AJAX aura son jeton unique. Le 2ième demande, le jeton que vous venez d'utiliser est supprimé.

Après avoir obtenu le jeton, je l'ajoute en tant que paramètre au lien que je demande, quelque chose comme ceci:

ajaxRequestObjet = $.ajax({
    url: "http://localhost:8084/mywebsite.com/servlet", //<-- local Tomcat server
    method: "POST",
    data: "type=AJAX&page=some-article&token=fmf5p81m6e56n4va3nkfu2ns8n"
});

Cette méthode fonctionne bien contre quelqu'un qui inspecte le site Web manuellement et essaie d'utiliser les liens, mais qu'en est-il des serveurs Java/php/IIS qui le font automatiquement?

Pour cela, demandez l'en-tête! Quelque chose comme ça:

boolean isAjax = "XMLHttpRequest".equals(request.getHeader("X-Requested-With")); 

Ce sera vrai seulement et seulement si XMLHttpRequest existe ....

Il y a une dernière chose à garder à l'esprit. Assure-toi 'Access-Control-Allow-Origin' header is NOT present in your app pour vous assurer que tout javascript NON présent sur votre serveur n'obtiendra pas les ressources du serveur. Si cet en-tête n'existe pas, chrome renverra ceci:

XMLHttpRequest cannot load http://localhost:8084/mywebsite.com/servlet. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost' is therefore not allowed access.

Le serveur Java était à Tomcat et j'avais un autre Apache pour ces tests, c'est le petit html présent dans Apache qui a donné l'erreur ci-dessus:

<html>
<head>
    <script src="http://code.jquery.com/jquery-latest.min.js" type="text/javascript"></script>

    <script>
    ajaxRequestObjet = $.ajax({
        url: "http://localhost:8084/mywebsite.com/servlet",
        method: "POST",
        data: "type=AJAX&page=Token"
    });

    ajaxRequestObjet.done(function (msg) { 
        alert(msg);
    });

    </script>

</head>
<body>
</body>
</html>
39
Alpha2k

Bien que vous ne puissiez pas contrôler ce 100% ... il y a quelques options ..

Essayez d'utiliser les mêmes méthodes que les gens utilisent avec les scripts Captcha.

Fondamentalement, lorsque l'utilisateur charge le formulaire/page .. Vous générez une chaîne/id aléatoire dans leur session PHP et le stockez .. Quand ils envoient les demandes ajax, demandez à votre vérification ajax d'ajouter également le chaîne/id et l'exiger avant d'autoriser une vérification sinon retourner un en-tête de 500 ou quelque chose.

En utilisant cette approche avec les sessions, vous pouvez définir une limite autorisée de vérifications (disons 5) et une fois que l'utilisateur a essayé plus de 5 vérifications, il est nécessaire de recharger la page ou d'effectuer une vérification humaine (par exemple Captcha). leur nombre .. Même autoriser un total de disons 30 en 1 heure/par IP ou quelque chose.

Utilisez également des événements intelligents pour déclencher lorsque la vérification ajax est terminée, par exemple, le changement de champ/onglet ou sur un bouton appuyez sur .. Ou lorsqu'un e-mail valide est détecté .. mais dites que .com.au se déclencherait deux fois.

Fondamentalement, même si quelqu'un a reniflé vos fichiers JS et a essayé d'automatiser le vérificateur d'e-mails. Il leur faudrait trouver un moyen d'ajouter la chaîne/id que vous générez et également limiter leur quantité de demandes effectuées.

Au-delà de cela, il n'y a pas grand chose de plus que vous pouvez faire facilement .. Mais il y a encore quelques autres idées.

La plupart d'entre eux contourneraient l'utilisation d'un PHP session/cookie .. Dites par exemple s'ils vérifient et trouvent 3 adresses e-mail .. Ensuite, vous définissez cela comme une limite et les forcez à exiger un soumission manuelle ou quelque chose.

Voyez comment la suggestion ci-dessus se passe pour vous, n'hésitez pas à poser toutes les questions. Mais cela peut me prendre un jour ou deux pour répondre comme un week-end. Recherchez également comment les scripts Captcha fonctionnent comme beaucoup de code source pour eux. Comme ils travaillent sur la même idée.

Délais de temps sera simplement mauvais/fera apparaître votre site lentement/bugera l'utilisateur en attendant une réponse.

Vous devez limiter le nombre de recherches par session/adresse IP. Sinon, il existe toujours un moyen de dépasser ces vérifications .. Fondamentalement, une fois qu'elles ont atteint une limite .. Forcer l'utilisateur/ip/session à attendre quelques minutes/heures et vérifiez-les avec un script Captcha pour qu'il ne puisse pas être scripté ...

Sécurité Javascript/Cacher la source

Bien que vous ne puissiez pas vraiment le faire, vous pouvez faire certaines choses pour générer le JS en utilisant une page PHP avec un en-tête JS .. donc <script src='myjscode.php'></script> et cela permet à PHP de rechercher une session valide .. Arrête donc les requêtes externes dans une certaine mesure .. Mais cela est surtout utile pour permettre à JS d'être uniquement disponible derrière une adhésion/connexion. .

Contrôles multiples/si possible dans ce cas

Selon votre approche, est-ce pour un utilisateur de vérifier s'il a déjà un compte? Si c'est le cas ... vous pouvez combiner la vérification par e-mail avec quelque chose comme leur nom/pays/âge/date de naissance ... Ils devraient donc sélectionner deux ou trois valeurs correspondantes correctes avant de pouvoir obtenir une vérification/réponse de l'appel ajax?

Peut-être pas dans votre cas, mais juste la pensée ajouterait cela aussi.

10
Angry 84

Le code JavaScript de votre site Web est exécuté sur l'ordinateur de l'utilisateur, vous ne pouvez donc pas l'empêcher de fouiller dans votre code. Même si vous utilisez un obfuscateur de code (par exemple, https://www.javascriptobfuscator.com/ ), le pirate pourrait déboguer votre application et enregistrer toutes les demandes envoyées au serveur.

Tout ce qui concerne la sécurité doit se produire sur le serveur. Vous pouvez limiter le nombre de demandes provenant d'une adresse IP spécifique.

9
Johannes Reuter

Ce type d'attaque peut être traité de la même manière que toute autre attaque par force brute, où la seule solution efficace consiste à utiliser un Captcha . Mais bien sûr, les Captchas sont au détriment de l'UX, vous devez donc vous demander si la sécurité supplémentaire en vaut la peine, en particulier pour une attaque qui a peu de chances de se produire de toute façon. Cela dit, vous pouvez de toute façon utiliser un Captcha sur votre formulaire d'inscription, pour empêcher les bots de créer des comptes.

Ce type d'attaque a un coût énorme pour peu de récompense pour l'attaquant. Il y a des milliards d'adresses e-mail possibles à tester. Cela ne pourrait valoir la peine d'aller aussi loin que si le site en question était particulièrement sensible, comme une sorte de site pour adultes, où l'attaquant espère faire chanter les utilisateurs qu'il trouve.

CloudFlare

Pas aussi bonne qu'une solution Captcha, mais l'attaque par force brute pourrait être détectée et empêchée par le système CloudFlare DDoS . De plus, CF peut forcer les utilisateurs de Tor à résoudre un Captcha avant d'accéder à votre site, ce qui empêcherait un attaquant d'utiliser Tor comme véhicule pour l'attaque.

Limitation du débit IP

La limitation du débit sur une base IP a des problèmes car si un attaquant décide d'entreprendre une tâche aussi énorme que cela, il utilisera probablement un Botnet ou un autre système de plusieurs machines pour lancer l'attaque.

Considérez une grande organisation telle qu'une université, où tous les utilisateurs partagent l'IP publique. L'un des utilisateurs lance une attaque sur votre site, et vous bloquez son IP, et dans les processus bloquant tout le monde. Cette contre-mesure pourrait en fait être utilisée pour lancer une attaque DoS .

ID de session/jeton CRSF

Certainement pas une solution car l'attaquant doit simplement faire une demande à la page en premier, pour obtenir le jeton. C'est une demande supplémentaire à faire mais seulement un inconvénient pour l'attaquant.

1
MrCode

Vous pouvez vous protéger contre les attaques par force brute avec quelque chose de similaire à jetons CSRF :

Attribuez un ID généré par le serveur à chaque session client. Chaque demande à check.php doit inclure cet ID.

check.php doit rejeter les demandes qui ne contiennent pas d'ID, ou inclure un ID que le serveur n'a pas généré (pour empêcher les attaques avec des ID falsifiés). Il doit également évaluer la limite de l'ID - si un ID donné a fait une demande (disons) la dernière seconde, ou si un ID donné fait plus de n demandes dans un intervalle de 10 secondes, il doit renvoyer une réponse d'erreur . Cela protège contre les demandes d'une seule session provenant de plusieurs adresses IP.

Vous devez également évaluer la limite par adresse IP pour éviter le forçage brutal en ouvrant un grand nombre de sessions d'application Web.

Il n'y a pas grand-chose que vous puissiez faire pour empêcher un attaquant de rechercher un seul ou un petit nombre d'adresses e-mail spécifiques - c'est un risque inhérent à ce type de validation.

1
joews

Tout d'abord: je coderais l'URL de l'adresse mail. 'example.com/check.php?email=' . urlencode([email protected])

Ajoutez votre question: lorsque check.php est appelé, vous pouvez

  • vérifier si la session de l'utilisateur et son IP ont envoyé une requête au cours des dernières secondes
  • sinon, écrivez la session de l'utilisateur, l'IP de l'utilisateur plus l'horodatage actuel dans une table d'assistance plus dans un cookie et frappez votre base de données
  • si oui, bloquez la demande

Mais je crains que cela ne vous aide pas contre la fraude car tout le monde peut vérifier votre JavaScript et si quelqu'un veut l'exploiter, il trouvera des moyens.

0
Stephan Weinhold