¿Por qué Google antepone while (1); a sus respuestas JSON?

4078

¿Por qué Google antepone while(1);sus respuestas JSON (privadas)?

Por ejemplo, aquí hay una respuesta al activar y desactivar un calendario en Google Calendar :

while (1);
[
  ['u', [
    ['smsSentFlag', 'false'],
    ['hideInvitations', 'false'],
    ['remindOnRespondedEventsOnly', 'true'],
    ['hideInvitations_remindOnRespondedEventsOnly', 'false_true'],
    ['Calendar ID stripped for privacy', 'false'],
    ['smsVerifiedFlag', 'true']
  ]]
]

Supongo que esto es para evitar que las personas hagan algo eval()al respecto, pero todo lo que realmente tendría que hacer es reemplazar el whiley luego estaría listo. Supongo que la prevención de evaluación es garantizar que las personas escriban un código de análisis JSON seguro.

También he visto esto usado en un par de otros lugares, pero mucho más con Google (Correo, Calendario, Contactos, etc.) Curiosamente, Google Docs comienza en su &&&START&&&lugar, y Google Contactos parece comenzar con while(1); &&&START&&&.

¿Que está pasando aqui?

Encadenar
fuente
45
Creo que tu primera impresión es correcta. Si comienza a buscar código e intenta recortar el flujo de entrada según la fuente, lo reconsideraría y lo haría de manera segura (y debido a las acciones de Google, más fácil).
Esteban Küber
34
probablemente una pregunta de seguimiento: ¿por qué Google antepone )]}'ahora en lugar de while(1);? ¿Serían las respuestas las mismas?
Gizmo
3
Evitaría evaluar, pero no con un bucle infinito.
Mardoxx
99
Esto )]}'también puede ser para guardar bytes, como Facebook usado for(;;);que ahorra un byte :)
Gras Double
3
Para evitar la divulgación de json, es decirJSON hijacking
Ashraf.Shk786

Respuestas:

4293

Impide el secuestro de JSON , un importante problema de seguridad de JSON que se corrige formalmente en todos los principales navegadores desde 2011 con ECMAScript 5.

Ejemplo contribuido: digamos que Google tiene una URL como la mail.google.com/json?action=inboxque devuelve los primeros 50 mensajes de su bandeja de entrada en formato JSON. Los sitios web malvados en otros dominios no pueden realizar solicitudes AJAX para obtener estos datos debido a la política del mismo origen, pero pueden incluir la URL a través de una <script>etiqueta. La URL se visita con sus cookies, y al anular el constructor de matriz global o los métodos de acceso pueden tener un método llamado cada vez que se establece un atributo de objeto (matriz o hash), lo que les permite leer el contenido JSON.

El while(1);o &&&BLAH&&&previene esto: una petición AJAX a mail.google.comtendrá acceso total al contenido del texto, y puede despojar a la basura. Pero una <script>inserción de etiqueta ejecuta ciegamente el JavaScript sin ningún procesamiento, lo que resulta en un bucle infinito o un error de sintaxis.

Esto no aborda el problema de la falsificación de solicitudes entre sitios .

rjh
fuente
228
¿Por qué la solicitud para obtener estos datos no requiere un token CSRF?
Jakub P.
235
¿Hace for(;;);el mismo trabajo? He visto esto en las respuestas ajax de Facebook.
Rey Julien
183
@JakubP. Almacenar y mantener tokens CSRF a escala de Google requiere una gran cantidad de infraestructura y costo.
abraham
127
@JakubP. los tokens anti-CSRF se mezclan con el almacenamiento en caché y requieren cierta cantidad de evaluación criptográfica del lado del servidor. A escala de Google, eso requeriría mucha CPU. Este tipo de descarga al cliente.
bluesmoon
96
Me parece que una mejor manera sería dejar que el servidor solo envíe el JSON si se ha configurado el encabezado correcto. Puede hacerlo en una llamada AJAX, pero no con etiquetas de script. De esa manera, la información confidencial nunca se envía, y no tiene que confiar en la seguridad del lado del navegador.
mcv
574

Impide la divulgación de la respuesta a través del secuestro de JSON.

En teoría, el contenido de las respuestas HTTP está protegido por la Política del mismo origen: las páginas de un dominio no pueden obtener ninguna información de las páginas del otro dominio (a menos que se permita explícitamente).

Un atacante puede solicitar páginas en otros dominios en su nombre, por ejemplo, usando una etiqueta <script src=...>o <img>, pero no puede obtener ninguna información sobre el resultado (encabezados, contenido).

Por lo tanto, si visita la página de un atacante, no podrá leer su correo electrónico de gmail.com.

Excepto que cuando se usa una etiqueta de script para solicitar contenido JSON, el JSON se ejecuta como Javascript en el entorno controlado de un atacante. Si el atacante puede reemplazar el constructor Array u Object o algún otro método utilizado durante la construcción del objeto, cualquier cosa en el JSON pasaría por el código del atacante y se divulgaría.

Tenga en cuenta que esto sucede en el momento en que JSON se ejecuta como Javascript, no en el momento en que se analiza.

Hay múltiples contramedidas:

Asegurarse de que el JSON nunca se ejecute

Al colocar una while(1);declaración antes de los datos JSON, Google se asegura de que los datos JSON nunca se ejecuten como Javascript.

Solo una página legítima podría obtener todo el contenido, eliminar el contenido while(1);y analizar el resto como JSON.

Cosas como for(;;);se han visto en Facebook, por ejemplo, con los mismos resultados.

Asegurarse de que el JSON no sea Javascript válido

Del mismo modo, agregar tokens no válidos antes del JSON, como &&&START&&&, asegura que nunca se ejecute.

Siempre devuelva JSON con un objeto en el exterior

Esta es una OWASPforma recomendada de proteger contra el secuestro de JSON y es la menos intrusiva.

Similar a las contramedidas anteriores, se asegura de que el JSON nunca se ejecute como Javascript.

Un objeto JSON válido, cuando no está encerrado por nada, no es válido en Javascript:

eval('{"foo":"bar"}')
// SyntaxError: Unexpected token :

Sin embargo, esto es válido JSON:

JSON.parse('{"foo":"bar"}')
// Object {foo: "bar"}

Por lo tanto, asegúrese de que siempre devuelve un Objeto en el nivel superior de la respuesta, asegúrese de que el JSON no sea Javascript válido, mientras siga siendo JSON válido.

Como señaló @hvd en los comentarios, el objeto vacío {}es Javascript válido, y saber que el objeto está vacío puede ser una información valiosa.

Comparación de los métodos anteriores.

La forma OWASP es menos intrusiva, ya que no necesita cambios en la biblioteca del cliente y transfiere JSON válidos. Sin embargo, no está claro si los errores pasados ​​o futuros del navegador podrían vencer esto. Como señaló @oriadam, no está claro si los datos podrían filtrarse en un error de análisis mediante un tratamiento de errores o no (por ejemplo, window.onerror).

La forma en que Google requiere la biblioteca del cliente para que sea compatible con la deserialización automática y puede considerarse más segura sobre los errores del navegador.

Ambos métodos requieren cambios en el lado del servidor para evitar que los desarrolladores envíen accidentalmente JSON vulnerables.

Arnaud Le Blanc
fuente
23
La recomendación de OWASP es interesante por su simplicidad. ¿Alguien sabe por qué el camino de Google es más seguro?
funroll
18
Creo que no es más seguro de ninguna manera. Proporcionar OWASP aquí parece una buena razón para +1.
30
Puede valer la pena señalar por qué devolver un literal de objeto falla la scriptetiqueta o evalfunción. Las llaves {}se pueden interpretar como un bloque de código o un objeto literal, y por sí mismo, JavaScript prefiere el primero. Como bloque de código es, por supuesto, inválido. Según esta lógica, no puedo ver ningún cambio previsible en el comportamiento futuro del navegador.
Manngo
16
El código incorrecto no es suficiente porque un atacante también puede secuestrar el controlador de errores de script del navegador ( window.onerror) No estoy seguro de cuál es el comportamiento de los onerrorerrores de sintaxis. Supongo que Google tampoco estaba seguro.
oriadam
12
"Un objeto JSON válido, cuando no está encerrado por nada, no es válido en Javascript:" - Excepto en el caso trivial de un objeto vacío ( {}), que también es un bloque vacío válido. Si saber que el objeto está vacío puede ser información valiosa, esto podría ser explotable.
371

Esto es para garantizar que algún otro sitio no pueda hacer trucos desagradables para intentar robar sus datos. Por ejemplo, al reemplazar el constructor de matriz , y luego incluir esta URL JSON a través de una <script>etiqueta, un sitio malicioso de terceros podría robar los datos de la respuesta JSON. Al poner un while(1);al principio, el script se bloqueará en su lugar.

Una solicitud del mismo sitio usando XHR y un analizador JSON separado, por otro lado, puede ignorar fácilmente el while(1);prefijo.

bdonlan
fuente
66
Técnicamente, un analizador JSON "normal" debería dar un error si tiene un prefijo.
Matthew Crumley
12
Los atacantes solo usarían un <script>elemento antiguo simple , no un XHR.
Laurence Gonsalves
99
@Matthew, claro, pero puedes eliminarlo antes de pasar los datos al analizador JSON. No puedes hacer eso con una <script>etiqueta
bdonlan
77
¿Hay algún ejemplo de esto? Se vuelve a hacer referencia al reemplazo del constructor de matrices, pero eso es un error solucionado durante mucho tiempo. No entiendo cómo se tendría acceso a los datos recibidos a través de la etiqueta del script. Me encantaría ver una implementación ficticia que funciona en un navegador reciente.
Dennis G
77
@joeltine, no, no lo es. Ver stackoverflow.com/questions/16289894/… .
111

Eso sería para dificultar que un tercero inserte la respuesta JSON en un documento HTML con la <script>etiqueta. Recuerde que la <script>etiqueta está exenta de la Política del mismo origen .

Daniel Vassallo
fuente
21
Esto es solo la mitad de una respuesta. Si no fuera por el truco de anular los constructores Objecty Array, ejecutar una respuesta JSON válida como si fuera JavaScript sería totalmente inocuo en todas las circunstancias. Sí, while(1);evita que la respuesta se ejecute como JavaScript si está dirigida por una <script>etiqueta, pero su respuesta no explica por qué es necesario.
Mark Amery
pero cómo evitará los iframes
Ravinder Payal
La etiqueta de script nunca está exenta de la misma política de origen. ¿Podrías aclararme eso?
Suraj Jain
82

Nota : a partir de 2019, muchas de las viejas vulnerabilidades que conducen a las medidas preventivas discutidas en esta pregunta ya no son un problema en los navegadores modernos. Dejaré la respuesta a continuación como una curiosidad histórica, pero realmente todo el tema ha cambiado radicalmente desde 2010 (!!) cuando se preguntó esto.


Impide que se use como objetivo de una <script>etiqueta simple . (Bueno, no lo previene, pero lo hace desagradable.) De esa manera, los malos no pueden simplemente poner esa etiqueta de script en su propio sitio y confiar en una sesión activa para que sea posible recuperar su contenido.

editar : tenga en cuenta el comentario (y otras respuestas). La cuestión tiene que ver con subvertido incorporado de instalaciones, específicamente las Objecty Arrayconstructores. Esos pueden ser alterados de tal manera que JSON, de otra manera inocuo, cuando se analiza, podría desencadenar el código del atacante.

Puntiagudo
fuente
17
Esto es solo la mitad de una respuesta. Si no fuera por el truco de anular los constructores Objecty Array, ejecutar una respuesta JSON válida como si fuera JavaScript sería totalmente inocuo en todas las circunstancias. Sí, while(1);evita que la respuesta se ejecute como JavaScript si está dirigida por una <script>etiqueta, pero su respuesta no explica por qué es necesario.
Mark Amery
11

Dado que la <script>etiqueta está exenta de la Política del mismo origen, que es una necesidad de seguridad en el mundo web, while(1)cuando se agrega a la respuesta JSON evita el mal uso de la misma en la <script>etiqueta.

Krishna Ganeriwal
fuente