web-dev-qa-db-fra.com

JSON Hijacking est-il toujours un problème dans les navigateurs modernes?

J'utilise Backbone.js et le serveur Web Tornado. Le comportement standard pour la réception des données de collecte dans Backbone consiste à envoyer un tableau JSON.

Par ailleurs, le comportement standard de Tornado est de ne pas autoriser les tableaux JSON en raison de la vulnérabilité suivante:

http://haacked.com/archive/2008/11/20/anatomy-of-a-subtle-json-vulnerability.aspx

Un lien est: http://haacked.com/archive/2009/06/25/json-hijacking.aspx

Il me semble plus naturel de ne pas avoir à envelopper mon code JSON dans un objet lorsqu'il s'agit d'une liste d'objets.

Je n’étais pas en mesure de reproduire ces attaques dans les navigateurs modernes (c’est-à-dire les versions actuelles de Chrome, Firefox, Safari et IE9). En même temps, je n’étais pas en mesure de confirmer nulle part que les navigateurs modernes avaient résolu ces problèmes.

Pour m'assurer que je ne suis pas induit en erreur par d'éventuelles mauvaises compétences en programmation ni par de faibles compétences en recherche sur Google:

Ces attaques de piratage JSON sont-elles toujours un problème pour les navigateurs modernes?

(Remarque: Désolé pour le doublon possible à: Est-il possible de faire un 'détournement de JSON' sur un navigateur moderne? mais puisque la réponse acceptée ne semble pas répondre à la question - je pensais qu'il était temps de demander à nouveau et obtenir des explications plus claires.)

141
Rocketman

Non, il n'est plus possible de capturer les valeurs passées à la [] ou {} constructeurs dans Firefox 21, Chrome 27, ou IE 10.). Voici une petite page de test, basée sur les principales attaques décrites dans http : //www.thespanner.co.uk/2011/05/30/json-hijacking/ :

( http://jsfiddle.net/ph3Uv/2/ )

var capture = function() {
    var ta = document.querySelector('textarea')
        ta.innerHTML = '';
        ta.appendChild(document.createTextNode("Captured: "+JSON.stringify(arguments)));
        return arguments;
}
var original = Array;

var toggle = document.body.querySelector('input[type="checkbox"]');
var toggleCapture = function() {
    var isOn = toggle.checked;
    window.Array = isOn ? capture : original;
    if (isOn) {
        Object.defineProperty(Object.prototype, 'foo', {set: capture});    
    } else {
        delete Object.prototype.foo;
    }
};
toggle.addEventListener('click', toggleCapture);
toggleCapture();

[].forEach.call(document.body.querySelectorAll('input[type="button"]'), function(el) {
    el.addEventListener('click', function() {
        document.querySelector('textarea').innerHTML = 'Safe.';
        eval(this.value);
    });
});
<div><label><input type="checkbox" checked="checked"> Capture</label></div>
<div><input type="button" value="[1, 2]" /> <input type="button" value="Array(1, 2);" /> <input type="button" value="{foo: 'bar'}" /> <input type="button" value="({}).foo = 'bar';" /></div>
<div><textarea></textarea></div>

Il remplace window.Array et ajoute un passeur à Object.prototype.foo et teste l’initialisation de tableaux et d’objets via les formes courte et longue.

Dans la section 1.5, spécification ES4 , "exige que les liaisons globales standard d'Object et de Tableau soient utilisées pour construire de nouveaux objets pour les initialiseurs d'objet et de tableau", et note dans Implementation Precedent que "Internet Explorer 6, Opera 9.20 et Safari 3 ne respectent pas les rapprochements locaux ou globaux des objets Object et Array, mais utilisent les constructeurs Object et Array d’origine. "Ceci est conservé dans ES5, section 11.1 .4 .

Allen Wirfs-Brock a expliqué que ES5 spécifie également que l'initialisation de l'objet ne doit pas déclencher de paramètres, car elle utilise DefineOwnProperty. MDN: Travailler avec des objets note que "à partir de JavaScript 1.8.1, les paramètres ne sont plus appelés lors de la définition des propriétés dans les initialiseurs d'objet et de tableau". Ce problème a été traité dans V8, numéro 1015 .

107
user69173