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

4276

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

Por ejemplo, aquí tienes una respuesta al encender y apagar 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']
  ]]
]

Asumiría que esto es para evitar que la gente lo haga eval(), pero todo lo que realmente tienes que hacer es reemplazar el whiley luego estarás listo. Asumiría que la prevención de evaluación es asegurarse de que las personas escriban un código de análisis JSON seguro.

También he visto que esto se usa en un par de otros lugares, pero mucho más con Google (correo, calendario, contactos, etc.). Curiosamente, Google Docs comienza con &&&START&&&y los contactos de Google parecen comenzar con while(1); &&&START&&&.

¿Que está pasando aqui?

4
  • 48
    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á y lo hará de manera segura (y debido a las acciones de Google, más fácil). Esteban Küber 19/04/10 a las 18:04
  • 41
    probablemente una pregunta de seguimiento: ¿Por qué google antepone )]}'ahora en lugar de while(1);? ¿Serían las mismas respuestas? Gizmo 16 de febrero de 2017 a las 18:51
  • 3
    Evitaría eval, pero no con un bucle infinito. Mardoxx 6 de mayo de 2017 a las 20:27
  • 14
    Esto )]}'también puede ser para ahorrar bytes, como Facebook usado for(;;);que ahorra un byte :)Gras Double 8/07/2017 a las 20:55
4438

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

Ejemplo artificial: 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 la matriz global o los métodos de acceso, se puede llamar a un método 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&&&evita esto: una solicitud AJAX mail.google.comtendrá acceso completo al contenido del texto y puede eliminarlo. Pero la <script>inserción de una etiqueta ejecuta ciegamente 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 .

5
  • 240
    ¿Por qué la solicitud para obtener estos datos no requiere un token CSRF en su lugar? Jakub P. 3 de febrero de 2013 a las 1:43
  • 5
    ¿No resolvería también el problema devolver un objeto que contenga la matriz, en lugar de la matriz directamente? Pedro Felix 3 feb 2013 a las 18:26
  • 4
    @PedroFelix No, eso no resolvería el problema ya que los mismos ataques mencionados en la publicación aún podrían realizarse. Anulando los métodos de acceso para recuperar la información. Boushley 5 de febrero de 2013 a las 2:36
  • 191
    @JakubP. Almacenar y mantener tokens CSRF a la escala de Google requiere una gran cantidad de infraestructura y costo. abraham 5 de febrero de 2013 a las 5:12
  • 137
    @JakubP. Los tokens anti-CSRF interfieren 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. De esta forma, se lo descarga al cliente. bluesmoon 5 de febrero de 2013 a las 6:10
610

Evita la divulgación de la respuesta mediante el 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 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, mediante el uso de 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 secuencia de comandos 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 a través del código del atacante y se revelarí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.

Existen múltiples contramedidas:

Asegurarse de que 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, eliminarlo while(1);y analizar el resto como JSON.

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

Asegurarse de que JSON no sea JavaScript válido

De manera similar, 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 la forma recomendada por OWASP de protegerse del secuestro de JSON y es la menos intrusiva.

De manera similar a las contramedidas anteriores, se asegura de que JSON nunca se ejecute como JavaScript.

Un objeto JSON válido, cuando no está incluido por nada, no es válido en JavaScript:

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

Sin embargo, esto es JSON válido:

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

Por lo tanto, asegurarse de devolver siempre un Objeto en el nivel superior de la respuesta asegura que el JSON no sea JavaScript válido, mientras sigue 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 en sí mismo información valiosa.

Comparación de los métodos anteriores

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

El método de Google requiere una biblioteca cliente para que admita la deserialización automática y pueda considerarse más seguro con respecto a los errores del navegador.

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

3
  • 23
    La recomendación de OWASP es interesante por su simplicidad. ¿Alguien sabe una razón por la que el método de Google es más seguro? funroll 15 de marzo de 2014 a las 1:47
  • 18
    Creo que no es más seguro de ninguna manera. Proporcionar OWASP aquí parece una razón suficiente para hacer +1. user719662 12/04/2014 a las 15:54
  • Supongo que si debe usar JSONP, podría intentar usar tokens CSRF de alguna manera inteligente (probablemente insegura). Kelsey Francis 29 de agosto de 2014 a las 2:19
380

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

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

0
112

Eso dificultaría 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 de Mismo Origen .

0
83

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.


Evita que se utilice como destino 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 secuencia de comandos en su propio sitio y depender de una sesión activa para que sea posible buscar su contenido.

editar : anote el comentario (y otras respuestas). El problema tiene que ver con las instalaciones empotradas subvertidas, específicamente los constructores Objecty Array. Esos pueden modificarse de modo que JSON, que de otro modo sería inocuo, cuando se analiza, podría desencadenar un código atacante.

0
12

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 uso indebido de la misma en la <script>etiqueta.

2

Como esta es una publicación de alto tráfico, espero proporcionar aquí una respuesta un poco más indeterminada a la pregunta original y, por lo tanto, brindar más antecedentes sobre un ataque de secuestro de JSON y sus consecuencias.

El secuestro de JSON, como su nombre indica, es un ataque similar a la falsificación de solicitudes entre sitios, donde un atacante puede acceder a datos JSON confidenciales entre dominios desde aplicaciones que devuelven datos confidenciales como literales de matriz para solicitudes GET. A continuación, se muestra un ejemplo de una llamada JSON que devuelve un literal de matriz:

[{"id":"1001","ccnum":"4111111111111111","balance":"2345.15"}, 
{"id":"1002","ccnum":"5555555555554444","balance":"10345.00"}, 
{"id":"1003","ccnum":"5105105105105100","balance":"6250.50"}]

Este ataque se puede lograr en 3 pasos principales:

Paso 1: Consiga que un usuario autenticado visite una página maliciosa. Paso 2: La página maliciosa intentará acceder a datos confidenciales de la aplicación en la que el usuario inició sesión. Esto se puede hacer incrustando una etiqueta de secuencia de comandos en una página HTML, ya que la política del mismo origen no se aplica a las etiquetas de secuencia de comandos.

<script src="http://<jsonsite>/json_server.php"></script>

El navegador realizará una solicitud GET json_server.phpy las cookies de autenticación del usuario se enviarán junto con la solicitud. Paso 3: En este punto, mientras el sitio malicioso ha ejecutado el script, no tiene acceso a ningún dato sensible. Se puede obtener acceso a los datos mediante el uso de un generador de prototipos de objetos. En el código siguiente, una propiedad de prototipos de objeto se vincula a la función definida cuando se intenta establecer la ccnumpropiedad " ".

Object.prototype.__defineSetter__('ccnum',function(obj){
    secrets =secrets.concat(" ", obj);
});

En este punto, el sitio malicioso ha secuestrado con éxito los datos financieros confidenciales (ccnum)devueltos byjson_server.php JSON

Cabe señalar que no todos los navegadores admiten este método; La prueba de concepto se realizó en Firefox 3.x.Este método ahora ha sido obsoleto y reemplazado por el useObject.definePropertyTambién hay una variación de este ataque que debería funcionar en todos los navegadores donde pi=3.14159se devuelve JavaScript con nombre completo (por ejemplo ) en lugar de una matriz JSON .

Hay varias formas de prevenir el secuestro de JSON:

  • Dado que las etiquetas SCRIPT solo pueden generar solicitudes HTTP GET, solo devuelven objetos JSON a solicitudes POST.

  • Evite que el navegador web interprete el objeto JSON como código JavaScript válido.

  • Implemente la protección contra la falsificación de solicitudes entre sitios requiriendo que se requiera un valor aleatorio predefinido para todas las solicitudes JSON.

así que como puede ver While(1)viene bajo la última opción. En los términos más simples, while(1) es un bucle infinito que se ejecutará hasta que se emita explícitamente una declaración de interrupción. Y, por lo tanto, lo que se describiría como un bloqueo para que se aplique la clave (declaración de ruptura de Google). Por lo tanto, un secuestro de JSON, en el que el pirata informático no tiene clave, se descartará constantemente. Además, si lee el bloque JSON con un analizador, el bucle while (1) se ignora.

Entonces, en conclusión, el while(1)bucle se puede visualizar más fácilmente como un simple cifrado de declaración de ruptura que Google puede usar para controlar el flujo de datos.

Sin embargo, la palabra clave en esa declaración es la palabra " simple ". Afortunadamente, el uso de bucles infinitos autenticados se ha eliminado de la práctica básica en los años desde 2010 debido a su absoluta aniquilación del uso de CPU cuando está aislado (y el hecho de que Internet se ha alejado de forzar a través de crudos 'arreglos rápidos'). Hoy, en cambio, el código base tiene medidas preventivas integradas y el sistema ya no es crucial ni efectivo. (parte de esto es el alejamiento del secuestro de JSON a técnicas de cultivo de datos más fructíferas en las que no entraré en este momento)

0

After authentication is in place, JSON hijacking protection can take a variety of forms. Google appends while(1) into their JSON data, so that if any malicious script evaluates it, the malicious script enters an infinite loop.

Referencia: Libro de recetas de pruebas de seguridad web: Técnicas sistemáticas para encontrar problemas rápidamente