¿Cómo evito XSS (scripting entre sitios) usando solo HTML y PHP?
He visto muchas otras publicaciones sobre este tema, pero no he encontrado un artículo que indique de manera clara y concisa cómo prevenir realmente XSS.
Solo una nota de que esto no resolverá el caso en que desee utilizar la entrada del usuario como un atributo HTML. Por ejemplo, la URL de origen de una imagen. No es un caso común, pero fácil de olvidar.
@TimTim: para la mayoría de los casos, sí. Sin embargo, cuando necesita permitir la entrada de HTML, las cosas se ponen un poco más complicadas y, si este es el caso, le recomiendo que use algo como htmlpurifier.org
Alix Axel
@Alix Axel, entonces, ¿es su respuesta usar htmlspecialchars o htmlpurifier.org ?
TimTim
3
Si necesita aceptar la entrada HTML, use HTML Purifier, si no lo usa htmlspecialchars().
La mayoría de las veces es correcto, pero no es tan simple como eso. Debería considerar poner una cadena no confiable en HTML, Js, Css, y considerar poner HTML no confiable en HTML. Mira esto: owasp.org/index.php/…
hombre de bronce
41
Una de mis referencias favoritas de OWASP es la explicación de Cross-Site Scripting porque, si bien hay una gran cantidad de vectores de ataque XSS, ¡el seguir algunas reglas puede defenderse contra la mayoría de ellas!
Uno de los pasos más importantes es desinfectar cualquier entrada del usuario antes de que se procese y / o se devuelva al navegador. PHP tiene algunas funciones de " filtro " que pueden usarse.
La forma que suelen tener los ataques XSS es insertar un enlace a algún javascript externo que contenga intenciones maliciosas para el usuario. Lea más sobre esto aquí .
También querrás probar tu sitio. Puedo recomendar el complemento XSS Me de Firefox .
¿Qué necesito para asegurarme de desinfectar la entrada exactamente? ¿Hay un carácter / cadena en particular que debo tener en cuenta?
TimTim
27
@TimTim - no. Toda la entrada de usuario debe siempre ser considerado como hostil inherentemente.
zombat
Además, los datos internos (empleados, administradores de sistemas, etc.) podrían ser inseguros. Debe identificar y monitorear (con la fecha de registro y el usuario) los datos que se muestran con interpretación.
Samuel Dauzon
9
En orden de preferencia:
Si está utilizando un motor de plantillas (por ejemplo, Twig, Smarty, Blade), compruebe que ofrece un escape sensible al contexto. Sé por experiencia que Twig sí.{{ var|e('html_attr') }}
Si desea permitir HTML, use HTML Purifier . Incluso si cree que solo acepta Markdown o ReStructuredText, aún desea purificar la salida HTML de estos lenguajes de marcado.
De lo contrario, use htmlentities($var, ENT_QUOTES | ENT_HTML5, $charset)y asegúrese de que el resto de su documento use el mismo juego de caracteres que $charset. En la mayoría de los casos, 'UTF-8'es el conjunto de caracteres deseado.
Publicación cruzada de esto como referencia consolidada de la versión beta de SO Documentation que se desconecta.
Problema
La secuencia de comandos entre sitios es la ejecución involuntaria de código remoto por parte de un cliente web. Cualquier aplicación web puede exponerse a XSS si recibe información de un usuario y la envía directamente a una página web. Si la entrada incluye HTML o JavaScript, el código remoto se puede ejecutar cuando el cliente web presenta este contenido.
Por ejemplo, si un lado de terceros contiene un archivo JavaScript:
Se ejecutará el JavaScript de terceros y el usuario verá "Estoy ejecutando" en la página web.
Solución
Como regla general, nunca confíe en la información proveniente de un cliente. Cada valor GET, POST y cookie puede ser cualquier cosa y, por lo tanto, debe validarse. Al generar cualquiera de estos valores, escape de ellos para que no se evalúen de manera inesperada.
Tenga en cuenta que incluso en las aplicaciones más simples, los datos se pueden mover y será difícil hacer un seguimiento de todas las fuentes. Por lo tanto, es una buena práctica escapar siempre de la salida.
PHP proporciona algunas formas de escapar de la salida según el contexto.
htmlspecialcharsconvertirá los "caracteres especiales HTML" en sus codificaciones HTML, lo que significa que no se procesarán como HTML estándar. Para arreglar nuestro ejemplo anterior usando este método:
<?php
echo '<div>'. htmlspecialchars($_GET['input']).'</div>';// or
echo '<div>'. filter_input(INPUT_GET,'input', FILTER_SANITIZE_SPECIAL_CHARS).'</div>';
Todo lo que esté dentro de la <div>etiqueta no será interpretado como una etiqueta JavaScript por el navegador, sino como un simple nodo de texto. El usuario verá con seguridad:
Al generar una URL generada dinámicamente, PHP proporciona la urlencodefunción para generar de manera segura URL válidas. Entonces, por ejemplo, si un usuario puede ingresar datos que se convierten en parte de otro parámetro GET:
Cualquier entrada maliciosa se convertirá en un parámetro de URL codificado.
Uso de bibliotecas externas especializadas o listas OWASP AntiSamy
Algunas veces querrá enviar HTML u otro tipo de entradas de código. Deberá mantener una lista de palabras autorizadas (lista blanca) y no autorizadas (lista negra).
Puede descargar listas estándar disponibles en el sitio web de OWASP AntiSamy . Cada lista es adecuada para un tipo específico de interacción (ebay api, tinyMCE, etc.). Y es de código abierto.
Existen bibliotecas para filtrar HTML y evitar ataques XSS para el caso general y que funcionan al menos tan bien como las listas de AntiSamy con un uso muy fácil. Por ejemplo, tienes HTML Purifier
Muchos marcos ayudan a manejar XSS de varias maneras. Al rodar el suyo propio o si hay alguna preocupación de XSS, podemos aprovechar filter_input_array (disponible en PHP 5> = 5.2.0, PHP 7.) Normalmente agregaré este fragmento a mi SessionController, porque todas las llamadas pasan allí antes que cualquier otro controlador interactúa con los datos. De esta manera, todas las entradas del usuario se desinfectan en 1 ubicación central. Si esto se hace al comienzo de un proyecto o antes de que su base de datos se envenene, no debería tener ningún problema al momento de la salida ... detiene la basura, la basura sale.
/* Prevent XSS input */
$_GET = filter_input_array(INPUT_GET, FILTER_SANITIZE_STRING);
$_POST = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);/* I prefer not to use $_REQUEST...but for those who do: */
$_REQUEST =(array)$_POST +(array)$_GET +(array)$_REQUEST;
Lo anterior eliminará TODAS las etiquetas HTML y script. Si necesita una solución que permita etiquetas seguras, basadas en una lista blanca, consulte HTML Purifier .
Si su base de datos ya está envenenada o si desea tratar con XSS en el momento de la salida, OWASP recomienda crear una función de envoltura personalizada echoy usarla EN TODAS PARTES para obtener valores proporcionados por el usuario:
También puede configurar algunos encabezados de respuesta HTTP relacionados con XSS a través de header(...)
Protección X-XSS "1; modo = bloque"
para estar seguro, el modo de protección XSS del navegador está habilitado.
Content-Security-Policy "default-src 'self'; ..."
para habilitar la seguridad del contenido del lado del navegador. Consulte este para obtener detalles de la Política de seguridad de contenido (CSP): http://content-security-policy.com/
Especialmente, configurar CSP para bloquear scripts en línea y fuentes de scripts externos es útil contra XSS.
Obviamente, también intente evitarlo eval(var), si tiene que usar alguno de ellos, intente escapar de JS , escapar de HTML y es posible que tenga que hacer algo más, pero para lo básico esto debería ser suficiente.
href
osrc
atributo HTML: stackoverflow.com/questions/19047119/…Respuestas:
Básicamente, debe usar la función
htmlspecialchars()
siempre que desee enviar algo al navegador que provenga de la entrada del usuario.La forma correcta de usar esta función es algo como esto:
Google Code University también tiene estos videos muy educativos sobre seguridad web:
Cómo romper el software web: una mirada a las vulnerabilidades de seguridad en el software web
Lo que todo ingeniero necesita saber sobre la seguridad y dónde aprenderla
fuente
htmlspecialchars()
.Una de mis referencias favoritas de OWASP es la explicación de Cross-Site Scripting porque, si bien hay una gran cantidad de vectores de ataque XSS, ¡el seguir algunas reglas puede defenderse contra la mayoría de ellas!
Esta es la hoja de trucos de seguridad de PHP
fuente
Uno de los pasos más importantes es desinfectar cualquier entrada del usuario antes de que se procese y / o se devuelva al navegador. PHP tiene algunas funciones de " filtro " que pueden usarse.
La forma que suelen tener los ataques XSS es insertar un enlace a algún javascript externo que contenga intenciones maliciosas para el usuario. Lea más sobre esto aquí .
También querrás probar tu sitio. Puedo recomendar el complemento XSS Me de Firefox .
fuente
En orden de preferencia:
{{ var|e('html_attr') }}
htmlentities($var, ENT_QUOTES | ENT_HTML5, $charset)
y asegúrese de que el resto de su documento use el mismo juego de caracteres que$charset
. En la mayoría de los casos,'UTF-8'
es el conjunto de caracteres deseado.Además, asegúrese de escapar en la salida, no en la entrada .
fuente
Publicación cruzada de esto como referencia consolidada de la versión beta de SO Documentation que se desconecta.
Problema
La secuencia de comandos entre sitios es la ejecución involuntaria de código remoto por parte de un cliente web. Cualquier aplicación web puede exponerse a XSS si recibe información de un usuario y la envía directamente a una página web. Si la entrada incluye HTML o JavaScript, el código remoto se puede ejecutar cuando el cliente web presenta este contenido.
Por ejemplo, si un lado de terceros contiene un archivo JavaScript:
Y una aplicación PHP genera directamente una cadena que se le pasa:
Si un parámetro GET no verificado contiene,
<script src="http://example.com/runme.js"></script>
entonces la salida del script PHP será:Se ejecutará el JavaScript de terceros y el usuario verá "Estoy ejecutando" en la página web.
Solución
Como regla general, nunca confíe en la información proveniente de un cliente. Cada valor GET, POST y cookie puede ser cualquier cosa y, por lo tanto, debe validarse. Al generar cualquiera de estos valores, escape de ellos para que no se evalúen de manera inesperada.
Tenga en cuenta que incluso en las aplicaciones más simples, los datos se pueden mover y será difícil hacer un seguimiento de todas las fuentes. Por lo tanto, es una buena práctica escapar siempre de la salida.
PHP proporciona algunas formas de escapar de la salida según el contexto.
Funciones de filtro
Los PHP Funciones de filtro permiten que los datos de entrada al script php para ser desinfectado o validado en muchos sentidos . Son útiles al guardar o generar la entrada del cliente.
Codificación HTML
htmlspecialchars
convertirá los "caracteres especiales HTML" en sus codificaciones HTML, lo que significa que no se procesarán como HTML estándar. Para arreglar nuestro ejemplo anterior usando este método:Daría salida:
Todo lo que esté dentro de la
<div>
etiqueta no será interpretado como una etiqueta JavaScript por el navegador, sino como un simple nodo de texto. El usuario verá con seguridad:Codificación de URL
Al generar una URL generada dinámicamente, PHP proporciona la
urlencode
función para generar de manera segura URL válidas. Entonces, por ejemplo, si un usuario puede ingresar datos que se convierten en parte de otro parámetro GET:Cualquier entrada maliciosa se convertirá en un parámetro de URL codificado.
Uso de bibliotecas externas especializadas o listas OWASP AntiSamy
Algunas veces querrá enviar HTML u otro tipo de entradas de código. Deberá mantener una lista de palabras autorizadas (lista blanca) y no autorizadas (lista negra).
Puede descargar listas estándar disponibles en el sitio web de OWASP AntiSamy . Cada lista es adecuada para un tipo específico de interacción (ebay api, tinyMCE, etc.). Y es de código abierto.
Existen bibliotecas para filtrar HTML y evitar ataques XSS para el caso general y que funcionan al menos tan bien como las listas de AntiSamy con un uso muy fácil. Por ejemplo, tienes HTML Purifier
fuente
Muchos marcos ayudan a manejar XSS de varias maneras. Al rodar el suyo propio o si hay alguna preocupación de XSS, podemos aprovechar filter_input_array (disponible en PHP 5> = 5.2.0, PHP 7.) Normalmente agregaré este fragmento a mi SessionController, porque todas las llamadas pasan allí antes que cualquier otro controlador interactúa con los datos. De esta manera, todas las entradas del usuario se desinfectan en 1 ubicación central. Si esto se hace al comienzo de un proyecto o antes de que su base de datos se envenene, no debería tener ningún problema al momento de la salida ... detiene la basura, la basura sale.
Lo anterior eliminará TODAS las etiquetas HTML y script. Si necesita una solución que permita etiquetas seguras, basadas en una lista blanca, consulte HTML Purifier .
Si su base de datos ya está envenenada o si desea tratar con XSS en el momento de la salida, OWASP recomienda crear una función de envoltura personalizada
echo
y usarla EN TODAS PARTES para obtener valores proporcionados por el usuario:fuente
También puede configurar algunos encabezados de respuesta HTTP relacionados con XSS a través de
header(...)
para estar seguro, el modo de protección XSS del navegador está habilitado.
para habilitar la seguridad del contenido del lado del navegador. Consulte este para obtener detalles de la Política de seguridad de contenido (CSP): http://content-security-policy.com/ Especialmente, configurar CSP para bloquear scripts en línea y fuentes de scripts externos es útil contra XSS.
para obtener un conjunto general de encabezados de respuesta HTTP útiles sobre la seguridad de su aplicación web, consulte OWASP: https://www.owasp.org/index.php/List_of_useful_HTTP_headers
fuente
fuente
preg_replace
como se usaeval
en su entrada. owasp.org/index.php/PHP_Security_Cheat_Sheet#Code_InjectionUsar
htmlspecialchars
enPHP
. En HTML intente evitar usar:element.innerHTML = “…”; element.outerHTML = “…”; document.write(…); document.writeln(…);
donde
var
es controlado por el usuario .Obviamente, también intente evitarlo
eval(var)
, si tiene que usar alguno de ellos, intente escapar de JS , escapar de HTML y es posible que tenga que hacer algo más, pero para lo básico esto debería ser suficiente.fuente
La mejor manera de proteger su entrada es usar la
htmlentities
función. Ejemplo:Puedes obtener más información aquí .
fuente