¿Por qué Google antepone while(1); a sus respuestas JSON?
¿ 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 la gente haga algo eval()
en él, pero todo lo que realmente tendrías que hacer es reemplazarlo while
y luego estarías listo. Supongo que la prevención de evaluación es para asegurarse de que las personas escriban 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 Google Contacts parece comenzar con while(1); &&&START&&&
.
¿Que está pasando aqui?
Previene 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 mail.google.com/json?action=inbox
que devuelve los primeros 50 mensajes de su bandeja de entrada en formato JSON. Los sitios web maliciosos de otros dominios no pueden realizar solicitudes AJAX para obtener estos datos debido a la política del mismo origen, pero pueden incluir la URL mediante 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 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 en mail.google.com
tendrá acceso completo al contenido del texto y podrá eliminarlo. Pero la <script>
inserción de una etiqueta ejecuta JavaScript a ciegas 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 .
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 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, utilizando una etiqueta <script src=...>
o <img>
, pero no puede obtener ninguna información sobre el resultado (encabezados, contenidos).
Por lo tanto, si visita la página de un atacante, este no podrá leer su correo electrónico de gmail.com.
Excepto que cuando se utiliza 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 de matriz u objeto o algún otro método utilizado durante la construcción del objeto, cualquier contenido del JSON pasaría por el código del atacante y sería revelado.
Tenga en cuenta que esto sucede cuando el JSON se ejecuta como JavaScript, no cuando se analiza.
Existen múltiples contramedidas:
Asegurándose de que el JSON nunca se ejecute
Al colocar una while(1);
declaración antes de los datos JSON, Google garantiza que los datos JSON nunca se ejecuten como JavaScript.
Sólo una página legítima podría obtener todo el contenido, eliminarlo while(1);
y analizar el resto como JSON.
Cosas parecidas for(;;);
se han visto, por ejemplo, en Facebook, 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&&&
, garantiza que nunca se ejecute.
Siempre devuelve JSON con un objeto en el exterior
Esta es la forma recomendada por OWASP de protegerse contra el secuestro de JSON y es la menos intrusiva.
De manera 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, ya que se { }
interpreta como un bloque de código:
eval('{"foo":"bar"}')
// SyntaxError: Unexpected token :
Sin embargo, este es JSON válido:
JSON.parse('{"foo":"bar"}')
// Object {foo: "bar"}
Por lo tanto, asegúrese de devolver siempre un Objeto en el nivel superior de la respuesta y asegúrese de que el JSON no sea JavaScript válido, aunque 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 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 del cliente y transfiere JSON válido. Sin embargo, no está seguro si errores pasados o futuros del navegador podrían solucionar 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 del lado del servidor para evitar que los desarrolladores envíen accidentalmente JSON vulnerable.
Esto es para garantizar que otros sitios no puedan hacer trucos desagradables para intentar robar sus datos. Por ejemplo, al reemplazar el constructor de la matriz y luego incluir esta URL JSON mediante una <script>
etiqueta, un sitio de terceros malicioso podría robar los datos de la respuesta JSON. Al poner un while(1);
al principio, el script se bloqueará.
Por otro lado, una solicitud en el mismo sitio que utiliza XHR y un analizador JSON independiente puede ignorar fácilmente el while(1);
prefijo.