otro - ¿Necesito desinfectar el parámetro de devolución de llamada de una llamada JSONP?
jsonp ajax (4)
Desea asegurarse de que la devolución de llamada sea un identificador válido, que puede ser alfanumérico, guión bajo o $. Tampoco puede ser una palabra reservada (y para ser exhaustivo me aseguraré de que no esté undefined
, NaN
o Infinity
). Esta es la prueba que uso:
function valid_js_identifier( $callback ){
return !preg_match( ''/[^0-9a-zA-Z/$_]|^(abstract|boolean|break|byte|case|catch|char|class|const|continue|debugger|default|delete|do|double|else|enum|export|extends|false|final|finally|float|for|function|goto|if|implements|import|in|instanceof|int|interface|long|native|new|null|package|private|protected|public|return|short|static|super|switch|synchronized|this|throw|throws|transient|true|try|typeof|var|volatile|void|while|with|NaN|Infinity|undefined)$/'', $callback);
}
Muchas de las palabras reservadas no tienen sentido, pero algunas de ellas podrían causar errores o bucles infinitos.
Importante: no solo desinfecte la entrada reemplazando los caracteres; la devolución de llamada modificada podría ejecutarse sin errores y los datos devueltos no se manejarán correctamente (o incluso podrían manejarse con la función incorrecta). Desea probar si la entrada es válida y lanzar un error si no lo es. Esto evitará un comportamiento inesperado y notificará al desarrollador que se necesita una devolución de llamada diferente.
nota: esta es una versión más segura, pero limitada, de JSONP que no permite expresiones o refinamiento. He encontrado que funciona muy bien para la mayoría de las aplicaciones, especialmente si está usando jQuery y $.getJSON
Me gustaría ofrecer un servicio web a través de JSONP y me preguntaba si debo desinfectar el valor del parámetro de devolución de llamada.
Mi script actual del lado del servidor se ve así en este momento (más o menos. El código está en PHP, pero podría ser cualquier cosa):
header("Content-type: application/json; charset=utf-8");
echo $_GET[''callback''] . ''('' . json_encode($data) . '')'';
Esta es una vulnerabilidad XSS clásica.
Si necesito desinfectarla, ¿entonces cómo? No pude encontrar suficiente información sobre lo que podría estar permitido en las cadenas de devolución de llamada. Cito de Wikipedia :
Si bien el relleno (prefijo) suele ser el nombre de una función de devolución de llamada que se define dentro del contexto de ejecución del navegador, también puede ser una asignación de variable, una sentencia if o cualquier otro prefijo de sentencia de Javascript.
Sí, cuando la callback
es como
(function xss(x){evil()})
Cuando devuelvas el eco desde php, se verá como
(function xss(x){evil()})(json)
La función xss se ejecutará y evil () puede ser algunos códigos que envían cookies a otro lugar.
Entonces, desinfecte solo los nombres de funciones válidos, por ejemplo, limítelo a alfanumérico
Sí, necesitas sanear el parámetro de devolución de llamada.
JSONP es básicamente un ataque XSS autoinfligido. Cuando inserte (temporalmente) la etiqueta de secuencia de comandos con una url a un nombre de host diferente y permita que llame a una función o método global en su página, es importante tomar al menos algunas precauciones de que limite la "devolución de llamada" para que sea nada más que una devolución de llamada nombre.
Un nombre de devolución de llamada debe, sintácticamente, ser tan simple como un identificador. Usted podría hacer una concesión para las propiedades del objeto. Yo recomendaría no permitir paréntesis, ya que eso podría habilitar invocaciones de funciones, etc.
A continuación se muestra un ejemplo de una API básica que admite JSON y JSONP. Está escrito en PHP (simplificado a partir de la API de MediaWiki), pero se pueden crear estructuras similares en otros lenguajes de programación.
<?php
// Simulate the response data
$responseData = [
''foo'' => ''bar'',
''count'' => [''one'', ''two'', ''three''],
''total'' => 3,
];
// Prepare to send the response
$prefix = '''';
$suffix = '''';
$ctype = ''application/json'';
if (isset($_GET[''callback''])) {
$ctype = ''text/javascript'';
// Sanitize callback
$callback = preg_replace("/[^][.//'///"_A-Za-z0-9]/", '''', $_GET[''callback'']);
$prefix = $callback . ''('';
$suffix = '')'';
}
// Send the response
header("Content-Type: $ctype; charset=UTF-8", true);
print $prefix . json_encode($responseData) . $suffix;
exit;
Sí.
Según lo descrito por @YOU, un atacante podría crear un parámetro de devolución de llamada que evalúe el JavaScript malicioso o, lo que es peor, el Flash malicioso .
Validar que la devolución de llamada no es una palabra reservada y es alfanumérico como lo describe @ Brett-Wejrowski es un buen comienzo.
Google, Facebook y Github están mitigando la vulnerabilidad de Rosetta Flash al dejar pendiente un comentario vacío, como / ** /, a la devolución de llamada jsonp.
Otro enfoque sería devolver una expresión javascript más segura, como lo hace ExpressJS:
typeof callbackstring === ''function'' && callbackstring(.....);