JSONP

De Wikipedia, la enciclopedia libre
JSONP
www.json-p.org
(enlace roto, archivado en web archive)
Información general
Extensión de archivo .jsonp
Tipo de MIME application/json-p
Tipo de formato Intercambio de datos
Extendido de JSON y JavaScript
Estándar(es) RFC 7159, RFC 4329
Formato abierto Sí 

JSONP o JSON-P (JSON con relleno) es una técnica de JavaScript para solicitar datos cargando una etiqueta <script>. Fue propuesto por Bob Ippolito en 2005.[1]​ JSONP permite compartir datos sin pasar por la política del mismo origen, que no permite ejecutar código JavaScript para leer elementos del Modelo de Objetos de Documento (DOM) o datos XMLHttpRequest obtenidos desde fuera del sitio de origen de la página. El sitio de origen se indica mediante una combinación de esquema URI, nombre de host y número de puerto .

Funcionalidad[editar]

El elemento HTML <script> generalmente puede ejecutar código JavaScript recuperado de orígenes externos. Sin embargo, los servicios que respondieron con datos JSON puros no pueden compartir datos de orígenes externos antes de la adopción de CORS (intercambio de recursos de origen cruzado).

Por ejemplo, una solicitud a un servicio externo http://server.example.com/Users/1234 puede devolver un registro de una persona llamada Alice en el formato JSON. La sintaxis JSON es coherente con la sintaxis de objetos de JavaScript:

{
  "Name": "Alice",
  "Id": 1234,
  "Rank": 7
}

Sin soporte para CORS, un intento de usar los datos entre dominios da como resultado un error de JavaScript:

<script type="application/javascript"
    src="http://server.example.com/Users/1234">
</script>

El navegador descargará el archivo apuntado dentro de la etiqueta <script>, evaluará su contenido, malinterpretará los datos JSON sin procesar como un bloque y arrojará un error de sintaxis. Incluso si los datos se interpretaran como un literal de objeto de JavaScript, JavaScript no podría acceder a él cuando se ejecutara en el navegador, ya que sin una asignación variable, los literales de objeto son inaccesibles.

En el patrón de uso JSONP, la solicitud de URL señalada por el atributo src en el elemento <script> devuelve datos JSON, con un código JavaScript (generalmente una llamada a función) envuelto alrededor de él. Esta "carga útil envuelta" es interpretada por el navegador. De esta manera, una función que ya está definida en el entorno JavaScript puede manipular los datos JSON. A continuación se muestra una solicitud y respuesta JSONP típica.

La llamada a la función parseResponse() es la "P" de JSONP: el "relleno" o "prefijo" alrededor del JSON puro.[2]​ Para que JSONP funcione, un servidor debe entregar una respuesta que incluya la función JSONP. JSONP no funciona con resultados con formato JSON. El cliente y el servidor deben acordar la invocación de la función JSONP que se devuelve y la carga útil que recibe la función. Por convención, el servidor que proporciona los datos JSON ofrece al sitio web solicitante el nombre de la función JSONP, generalmente utilizando el nombre jsonp o devolución de llamada como parámetro de cadena de consulta con nombre, en su solicitud al servidor: <script src="http://server.example.com/Users/1234?callback=parseResponse"></script>.

En este ejemplo, la carga útil recibida sería:

parseResponse({"Name": "Alice", "Id": 1234, "Rank": 7});

Inyección de elementos de script[editar]

JSONP solo tiene sentido cuando se usa con un elemento de script. Para cada nueva solicitud JSONP, el navegador debe agregar un nuevo elemento <script> o reutilizar uno existente. La primera opción, agregar un nuevo elemento de secuencia de comandos, se realiza mediante la manipulación dinámica del DOM, y se conoce como inyección de elementos de secuencia de comandos. El elemento <script> se inyecta en el DOM HTML, con la URL del punto final JSONP deseado establecido como el atributo "src". Esta inyección dinámica de elementos de script generalmente se realiza mediante una biblioteca auxiliar de JavaScript. jQuery y otros framework tienen funciones de ayuda JSONP; También hay opciones independientes.

Un ejemplo de uso de jQuery para inyectar dinámicamente un elemento de script para una llamada JSONP se vería así:

$.getScript("http://server.example.com/Users/192.168.73.96?callback=parseResponse");

Después de inyectar el elemento, el navegador lo evalúa y realiza una petición HTTP GET en la URL src, recuperando el contenido. Luego, el navegador evalúa la carga útil de retorno como JavaScript. Esto es típicamente una invocación de función. De esa manera, el uso de JSONP puede permitir que las páginas del navegador eviten la política del mismo origen mediante la inyección de elementos de script.  

El script se ejecuta dentro del alcance de la página incluida y, como tal, todavía está sujeto a restricciones entre dominios en relación con el dominio de la página incluida. Esto significa que una página web no puede, por ejemplo, cargar una biblioteca alojada en otro sitio a través de JSONP y luego realizar solicitudes XMLHttpRequest a ese sitio (a menos que se admita el intercambio de recursos de origen cruzado (CORS)), aunque uno podría usar dicha biblioteca para hacer XMLHttpRequests en el propio sitio.

Preocupaciones de seguridad[editar]

Código de terceros no confiable[editar]

La inclusión de etiquetas de script desde servidores remotos permite a los servidores remotos inyectar cualquier contenido en un sitio web. Si los servidores remotos tienen vulnerabilidades que permiten la inyección de JavaScript, la página servida desde el servidor original está expuesta a un mayor riesgo. Si un atacante puede inyectar JavaScript en la página web original, ese código puede recuperar JavaScript adicional de cualquier dominio, sin pasar por la política del mismo origen.[3]​ El Encabezado HTTP de la Política de seguridad de contenido permite a los sitios web indicar a los navegadores web desde qué scripts de dominio se pueden incluir.

Se realizó un esfuerzo alrededor de 2011 para definir una definición de subconjunto estricta más segura para JSONP[4]​ que los navegadores podrían aplicar en las solicitudes de script con un tipo MIME específico como "application/json-p". Si la respuesta no se analizó como JSONP estricto, el navegador podría arrojar un error o simplemente ignorar la respuesta completa. Sin embargo, este enfoque fue abandonado a favor de CORS, y el tipo MIME correcto para JSONP sigue siendo application/javascript.[5]

Diferencias de espacios en blanco[editar]

JSONP tiene los mismos problemas que resolver JSON con eval(): ambos interpretan el texto JSON como JavaScript, lo que significa diferencias en el manejo de los caracteres unicode U+2028 (separador de línea) y U+2029 (separador de párrafo) de JSON propiamente dicho. Esto hace que algunas cadenas JSON no sean legales en JSONP; Los servidores que sirven JSONP deben escapar de estos caracteres antes de la transmisión.[6]

Devolución de llamada de manipulación de nombre y ataque de descarga de archivo reflejado[editar]

Los nombres de devolución de llamada no sanitizados pueden usarse para pasar datos maliciosos a los clientes, evitando las restricciones asociadas con el tipo de contenido de application/json, como se demuestra en el ataque de descarga de archivos reflejados (RFD) de 2014.[7]

Los puntos finales inseguros de JSONP también pueden inyectarse con datos maliciosos.[8]

Cross-site request forgery[editar]

Las implementaciones ingenuas de JSONP están sujetas a ataques de Cross-site request forgery (CSRF o XSRF).[9]​ Debido a que la etiqueta HTML <script> no respeta la política del mismo origen en las implementaciones del navegador web, una página maliciosa puede solicitar y obtener datos JSON que pertenecen a otro sitio. Esto permitirá que los datos codificados con JSON se evalúen en el contexto de la página maliciosa, posiblemente divulgando contraseñas u otros datos confidenciales si el usuario está actualmente conectado al otro sitio.

Esto es problemático solo si los datos codificados con JSON contienen información confidencial que no debe divulgarse a un tercero, y el servidor depende de la política del mismo origen del navegador para bloquear la entrega de la información confidencial.

Rosetta Flash[editar]

Rosetta Flash es una técnica de explotación que permite a un atacante explotar servidores con un punto final JSONP vulnerable al hacer que Adobe Flash Player crea que un applet Flash especificado por el atacante se originó en el servidor vulnerable. Flash Player implementa una política del mismo origen que le permite a uno hacer solicitudes (con cookies) y recibir respuestas del sitio de alojamiento. El applet puede enviar los datos recuperados al atacante. Este es un exploit de origen cruzado con un impacto similar a incrustar un applet Flash arbitrario en el dominio vulnerable. El exploit utiliza una carga útil de ActionScript compilada en un archivo SWF compuesto enteramente de caracteres alfanuméricos mediante la creación de una secuencia zlib con un encabezado particular y bloques DEFLATE con codificación Huffman ad hoc. El archivo SWF alfanumérico resultante solo se usa como parámetro de devolución de llamada de una llamada JSONP. Los sitios de alto perfil como Google, YouTube, Twitter, Yahoo!, Yandex, LinkedIn, eBay, Instagram y Tumblr fueron vulnerables hasta julio de 2014.[10]​ Esta vulnerabilidad fue descubierta y publicada por el ingeniero de seguridad de Google Michele Spagnuolo[11]​ en los CVE 2014-4671[12]​ y CVE 2014-5333.[13]​ La versión de lanzamiento de Adobe Flash Player 14.0.0.145, lanzada el 8 de julio de 2014, introdujo una validación más fuerte de los archivos Flash,[14]​ y en la versión 14.0.0.176, lanzada el 12 de agosto de 2014, finalmente implementó la corrección,[15]​ evitando esta vulnerabilidad de trabajar.

Historia[editar]

En julio de 2005, George Jempty sugirió que se anteponga una asignación de variable opcional a JSON.[16][17]​ La propuesta original para JSONP, donde el relleno es una función de devolución de llamada, parece haber sido hecha por Bob Ippolito en diciembre de 2005[18]​ y ahora es utilizada por muchas aplicaciones Web 2.0 como Dojo Toolkit, Google Web Toolkit y servicios web.

Véase también[editar]

Referencias[editar]

  1. Ippolito, Bob (5 de diciembre de 2005). «Remote JSON - JSONP». Bob Ippolito on Haskell, Python, Erlang, JavaScript, etc. (en inglés). Archivado desde el original el 8 de junio de 2012. Consultado el 10 de febrero de 2017. 
  2. «Experimental RDF result set to JSON translator». Archivado desde el original el 15 de noviembre de 2014. Consultado el 20 de febrero de 2012. 
  3. Ben Hayak (17 de octubre de 2014). «Same Origin Method Execution». Consultado el 22 de octubre de 2014. 
  4. «Safer cross-domain Ajax with JSON-P/JSONP». JSON-P.org. Archivado desde el original el 4 de marzo de 2016. Consultado el 30 de octubre de 2011. 
  5. Grey, Eli (27 de junio de 2010). «Is this safe for providing JSONP?». stackoverflow.com. Consultado el 7 de septiembre de 2012. 
  6. «JSON: The JavaScript subset that isn't». Magnus Holm. Archivado desde el original el 13 de mayo de 2012. Consultado el 16 de mayo de 2011. 
  7. Oren Hafif (2014). «Reflected File Download - A New Web Attack Vector». TrustWave. Archivado desde el original el 28 de marzo de 2015. Consultado el 25 de marzo de 2015. 
  8. «Practical JSONP injection». 
  9. Grossman, Jeremiah (27 de enero de 2006). «Advanced Web Attack Techniques using GMail». Consultado el 3 de julio de 2009. 
  10. Michele, Spagnuolo. «Abusing JSONP with Rosetta Flash». Archivado desde el original el 21 de julio de 2014. Consultado el 20 de julio de 2014. 
  11. «Google - list of software vulnerabilities discovered or fixed by Googlers». Consultado el 29 de julio de 2014. 
  12. «MITRE: CVE-2014-4671». Consultado el 29 de julio de 2014. 
  13. «MITRE: CVE-2014-5333». Consultado el 21 de agosto de 2014. 
  14. «Adobe Security Bulletin APSB14-17». Consultado el 29 de julio de 2014. 
  15. «Adobe Security Bulletin APSB14-18». Consultado el 21 de agosto de 2014. 
  16. «eval'ing JSON». 19 de julio de 2005. Archivado desde el original el 12 de febrero de 2006. 
  17. «json: Message: Re: Comments». 17 de agosto de 2005. 
  18. «Remote JSON - JSONP». from __future__ import *. Bob.pythonmac.org. 5 de diciembre de 2005. Archivado desde el original el 4 de diciembre de 2009. Consultado el 8 de septiembre de 2008. 

Enlaces externos[editar]