¿El secuestro de JSON sigue siendo un problema en los navegadores modernos?

149

Estoy usando Backbone.js y el servidor web Tornado. El comportamiento estándar para recibir datos de recopilación en Backbone es enviar como una matriz JSON.

Por otro lado, el comportamiento estándar de Tornado es no permitir JSON Array debido a la siguiente vulnerabilidad:

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

Una relacionada es: http://haacked.com/archive/2009/06/25/json-hijacking.aspx

Me parece más natural no tener que envolver mi JSON en un objeto cuando realmente es una lista de objetos.

No pude reproducir estos ataques en los navegadores modernos (es decir, Chrome, Firefox, Safari e IE9 actuales). Al mismo tiempo, no pude confirmar en ningún lado que los navegadores modernos hubieran abordado estos problemas.

Para asegurarme de no confundirme con las posibles habilidades de programación deficientes ni con las habilidades de búsqueda de Google:

¿Estos ataques de secuestro JSON siguen siendo un problema hoy en día en los navegadores modernos?

(Nota: Lo siento por el posible duplicado a: ¿Es posible hacer 'JSON secuestro' en el navegador moderno? Pero ya no parece la respuesta aceptada para responder a la pregunta - pensé que era el momento de pedir de nuevo y obtener algunas explicaciones más claras .)

Rocketman
fuente
usando eval? entonces posible de otro modo No. Si nada se ha alterado o cambiado en análisis sintácticos columna vertebral forma en respuesta debería tratar de estar a salvo
Deeptechtons
10
En términos generales, nunca debe acercarse a la seguridad web con la suposición de que alguien va a utilizar un navegador "moderno".
Lucas
77
@Luke - Vea el comentario a continuación a Reid. Gran punto en general, pero no estoy haciendo una pregunta de seguridad general. (Mis usuarios solo podrán autenticarse si están usando un navegador moderno en primer lugar).
Rocketman,
44
@Luke, a veces tenemos que seguir adelante y permitirnos desarrollar con patrones modernos (como REST en este caso: obtener datos es una operación GET y no debería ser otra cosa) sin protegernos de las amenazas antiguas si ahora parecen aplicarse solo a un público reducido Entonces, esta pregunta es realmente valiosa, para permitirle a uno evaluar si puede ignorar esta amenaza o no para su caso de aplicación. En algún momento, es muy probable que los usuarios con software muy obsoleto tengan otro tipo de amenazas (malware) de las cuales no podremos protegerlos de todos modos.
Frédéric
2
@jpaugh, ¿dónde ves esas suposiciones? Solo asumo un poco que esas personas con un software tan obsoleto son "desprotegibles" de todos modos. (Acerca de justificar el costo de mis patines, ya estaba acostumbrado a poner un tercio de su precio en patines de velocidad de carbono que se gastaron en menos de un tercio del tiempo que me lleva usar mis patines actuales. Y de todos modos, yo creo que valen la pena, siempre que te guste montarlos, que es mi caso.)
Frédéric

Respuestas:

112

No, ya no es posible con los valores de captura se pasan a la []o {}constructores en Firefox 21, Chrome 27, o IE 10. He aquí una pequeña página de prueba, sobre la base de los principales ataques descritos en http://www.thespanner.co.uk / 2011/05/30 / json-secuestro / :

( 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>

Anula window.Arrayy agrega un setter Object.prototype.fooy prueba inicializando matrices y objetos a través de las formas cortas y largas.

La especificación ES4 , en la sección 1.5, "requiere que se usen los enlaces globales y estándar de Object and Array para construir nuevos objetos para inicializadores de objetos y matrices" y notas en el precedente de implementación que "Internet Explorer 6, Opera 9.20 y Safari 3 hacen no respete los cambios locales o globales de Object y Array, sino que use los constructores originales Object y Array ". Esto se conserva en ES5, sección 11.1.4 .

Allen Wirfs-Brock explicó que ES5 también especifica que la inicialización de objetos no debe desencadenar establecedores, ya que utiliza DefineOwnProperty. MDN: Trabajar con objetos señala que "a partir de JavaScript 1.8.1, los configuradores ya no se llaman cuando se configuran propiedades en los inicializadores de objetos y matrices". Esto se abordó en V8 número 1015 .

jpaugh
fuente
28
En 2009, Brendan Eich sugirió que los navegadores que no evaluaban los scripts servían como application / json ( bugzilla.mozilla.org/show_bug.cgi?id=376957#c75 ), lo que todavía me parece una buena idea.
2
Tenga en cuenta que la POST CSRF ciega todavía es posible usando formularios, particularmente con la codificación de texto / sin formato, y debe ser derrotada usando tokens / nonces.
1
Sí a la POST CSRF. Gracias por toda su gran información aquí.
Rocketman
55
Su declaración es correcta cuando se refiere simplemente a la sobreescritura del constructor Array. Sin embargo, los microsofts IE y Edge siguen siendo vulnerables al secuestro de JSON UTF-7. Lo probé recientemente (y por diversión hoy nuevamente), y aún funciona.
user857990
2
UTF-16BE también, gracias a Gareth Heyes, blog.portswigger.net/2016/11/json-hijacking-for-modern-web.html
eel ghEEz