Escapar de salida de forma segura para html y campos de entrada

En mi web app, los usuarios pueden introducir datos de texto. Esta información puede ser mostrada a otros usuarios, y el autor original también puede volver atrás y editar sus datos. Estoy buscando la manera correcta para escapar de forma segura los datos.

Sólo estoy sql desinfección en el camino, así que todo lo que se almacena como se lee. Digamos que tengo «déjà vu» en la base de datos. O, para ser más extrema, un <script> etiqueta. Es posible que este puede ser válida, y ni siquiera maliciosamente la intención, de entrada.

Estoy usando htmlentities() en el camino de salida para asegurarse de que todo se había escapado. El problema es que el html y campos de entrada de tratar las cosas de manera diferente. Quiero para asegurarse de que es seguro en HTML, pero que el autor al editar el texto, se ve exactamente lo que se escribió en los campos de entrada. También estoy usando jQuery para rellenar los campos del formulario con los datos dinámicamente.

Si hago esto:

 <p><?=htmlentities("déjà vu");?></p>
 <input type=text value="<?=htmlentities("déjà vu");?>">

El código fuente de la página pone d&eacute;j&agrave; vu en ambos lugares (tuve que backtick que o te gustaría ver «déjà vu»!) El problema es que la salida en el <p> es correcta, pero la de entrada muestra el escape de texto. Si el usuario vuelve a enviar su formulario, doble escape y la ruina de su entrada.

Sé que todavía tengo que desinfectar el texto que va en el campo, de lo contrario usted puede terminar el valor de cotización y hacer cosas malas. La única solución que he encontrado es esto. De nuevo, estoy usando jQuery.

var temp = $("<div></div>").html("<?=htmlentities("déjà vu");?>");
$("input").val(temp.html());

Funciona esto, ya que hace que el div para leer el escape de texto como caracteres codificados y, a continuación, el jquery copias de los caracteres codificados a la etiqueta input, conservado adecuadamente.

Así que mi pregunta: es seguro todavía, o es que hay un agujero de seguridad en algún lugar? Y lo que es más importante, es esta la única /forma correcta de hacer esto? Me estoy perdiendo algo acerca de cómo html y la codificación de caracteres obras que hacen de este un tema trivial para resolver?

EDITAR

Esto es realmente malo, yo simplificada mi ejemplo hasta el punto de que no funciona. El problema es, en realidad, porque yo estoy usando jQuery val() para insertar el texto en el campo.

<input>
<script>$("input").val("<?=htmlentities("déjà vu");?>");</script>

La razón de esto es que el formulario es dinámico – el usuario puede agregar o quitar campos a voluntad y de manera que se generan después de la carga de la página.

Por lo que parece que jQuery es escapar de los datos para ir a la entrada, pero no es lo suficientemente bueno – si yo no hago nada de mí mismo, un usuario puede poner en un </script> etiqueta, matando mi código y la inserción de código malicioso. Pero hay otro argumento que se hizo aquí. Ya que sólo el autor original puede ver el texto en un cuadro de entrada de todos modos, debería siquiera se moleste? Básicamente, la gente sólo se podría ejecutar un ataque de XSS en contra de ellos mismos.

OriginalEl autor Tesserex | 2010-06-30

3 Kommentare

  1. 5

    Lo siento, pero no puedo reproducir el comportamiento que usted describe. Yo siempre he usado htmlspecialchars() (que es esencialmente la misma tarea como htmlentities()) y nunca conduce a ningún tipo de doble codificación. El código fuente de la página muestra d&eacute;j&agrave; vu en ambos lugares (¡por supuesto! ese es el punto!) pero el renderizado de la página muestra los valores apropiados y eso es lo envía de vuelta al servidor.

    Puedes publicar un completo auto-contenida fragmento de código que muestra tal comportamiento?

    Actualización: algunas pruebas de código:

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head><title></title>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
    </head>
    <body>
    
    <?php
    
    $default_value = 'déjà vu <script> ¿foo?';
    
    if( !isset($_GET['foo']) ){
        $_GET['foo'] = $default_value;
    }
    
    ?>
    
    <form action="" method="get">
        <p><?php echo htmlentities($_GET['foo']); ?></p>
        <input type="text" name="foo" value="<?php echo htmlentities($_GET['foo']); ?>">
        <input type="submit" value="Submit">
    </form>
    
    </body>
    </html>

    Respuesta a actualizado pregunta

    La htmlentities() función, como su nombre lo indica, se utiliza a la hora de generar código HTML de salida. Por eso es de poco uso en su segundo ejemplo: JavaScript es no HTML. Se trata de un lenguaje propio, con su propia sintaxis.

    Ahora, el problema que se quiere solucionar es cómo generar una salida que sigue a estas dos reglas:

    1. Es una cadena válida en JavaScript.
    2. Puede ser incorporado de forma segura en un documento HTML.

    El más cercano función de PHP para #1 soy consciente de que es json_encode(). Desde sintaxis JSON es un subconjunto de JavaScript, si la alimentas con una cadena PHP que es la salida de una cadena de JavaScript.

    Como sobre #2, una vez que el navegador entra en un bloque de JavaScript se espera un </script> etiqueta de salir de él. El json_encode() función se encarga de esto y escapa correctamente (<\/script>).

    Mi revisado el código de la prueba:

    <?php
    
    $default_value = 'déjà vu </script> ¿foo?';
    
    if( !isset($_GET['foo']) ){
        $_GET['foo'] = $default_value;
    }
    
    ?>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
    <html>
    <head><title></title>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
    <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
    <script type="text/javascript"><!--
    $(function(){
        $("input[type=text]").val(<?php echo json_encode(utf8_encode($_GET['foo'])); ?>);
    });
    //--></script>
    </head>
    <body>
    
    
    <form action="" method="get">
        <p><?php echo htmlentities($_GET['foo']); ?></p>
        <input type="text" name="foo" value="(to be replaced)">
        <input type="submit" value="Submit">
    </form>
    
    </body>
    </html>

    Nota: utf8_encode() convierte a partir de ISO-8859-1 a UTF-8 y no es necesaria si sus datos ya están en UTF-8 (recomendado).

    Estoy usando json_encode para este propósito en otras partes de mi código, vaya usted a saber! Gracias!

    OriginalEl autor Álvaro González

  2. 1

    Si usted simplemente necesita para revertir la codificación a continuación, puede utilizar html_entity_decode – http://www.php.net/manual/en/function.html-entity-decode.php.

    Otra posibilidad es solo ejecutar htmlentities en el momento en que el contenido se mostrará como parte de una página web. De lo contrario, mantenga el sin codificar texto, tal como fue presentado o cargados desde su almacén de datos.

    OriginalEl autor Frank

  3. 0

    Creo que es un problema con la forma en que se va a aplicar el valor hacia la entrada. Se muestran, como codificados, lo cual tiene sentido porque es Javascript, no en HTML. Así, lo que yo propondría es escribir su texto codificado como parte de la definición, de forma que se analiza de forma natural (en lugar de ser inyectado con el script de cliente). Desde su cuadros de texto no están disponibles cuando el servidor está respondiendo, puede utilizar temporal de un campo oculto…

    <input type="hidden" id="hidEncoded" value="<?=htmlentities("déjà vu");?>" />

    Luego será analizada como buen viejo HTML, y cuando intenta tener acceso al valor con Javascript debe ser decodificado…

    //Give your textbox an ID!
    $("#txtInput").val($("#hidEncoded").val());
    Bueno, eso es básicamente lo que mi solución dada fue. Acabo de utilizar jQuery para crear el elemento escondido a la derecha antes de poner el valor en el cuadro de texto. Usted incluso no necesita anexar la temp elemento del DOM para que funcione. Me sentí como que aún puede tener agujeros de seguridad o no ser el método óptimo.
    Creo que es subóptima en comparación a esto porque con su solución de script de cliente todavía está haciendo la inyección. Que aumenta las posibilidades de script malicioso de inyección (porque toda la cadena de entrada pasa a través de la intérprete de Javascript). Con mi solución, la cadena HTML se incluye como parte de una natural respuesta HTML (y es dentro de un atributo, por lo que la codificación es necesario y se espera) y, a continuación, Javascript lo saca después del hecho. Este es el limpiador, de la OMI.

    OriginalEl autor Josh Stodola

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein

Pruebas en línea