php - reflected - script para xss
¿Cómo prevenir XSS con HTML/PHP? (9)
¿Cómo puedo evitar que XSS (secuencias de comandos de sitios cruzados) use 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 el XSS.
En orden de preferencia:
- Si está utilizando un motor de plantillas (por ejemplo, Twig, Smarty, Blade), verifique que ofrezca un escape sensible al contexto. Sé por experiencia que Twig hace.
{{ var|e(''html_attr'') }}
- Si desea permitir HTML, use htmlpurifier.org . Incluso si cree que solo acepta Markdown o ReStructuredText, todavía desea purificar el HTML que generan 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 conjunto 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 .
Muchos marcos ayudan a manejar XSS de varias maneras. Al hacer rodar el suyo propio o si hay algún problema con XSS, podemos aprovechar filter_input_array (disponible en PHP 5> = 5.2.0, PHP 7.) Por lo general, agregaré este fragmento a mi SessionController, porque todas las llamadas pasan 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 problemas al momento de la salida ... detiene la basura, sale la basura.
/* 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 de script. Si necesita una solución que permita etiquetas seguras, basadas en una lista blanca, consulte el htmlpurifier.org .
Si su base de datos ya está envenenada o si desea lidiar con XSS en el momento de la salida, OWASP recomienda crear una función de envoltura personalizada para el echo
y usarla en TODAS PARTES, genera los valores proporcionados por el usuario:
//xss mitigation functions
function xssafe($data,$encoding=''UTF-8'')
{
return htmlspecialchars($data,ENT_QUOTES | ENT_HTML401,$encoding);
}
function xecho($data)
{
echo xssafe($data);
}
También puede configurar algunos encabezados de respuesta HTTP relacionados con XSS a través del header(...)
X-XSS-Protection "1; mode = block"
Sin duda, el modo de protección XSS del navegador está habilitado.
Política de seguridad de contenido "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 secuencias de comandos en línea y fuentes de secuencias de comandos externas es útil contra XSS.
Para obtener un conjunto general de encabezados de respuesta HTTP útiles relacionados con la seguridad de su aplicación web, consulte OWASP: https://www.owasp.org/index.php/List_of_useful_HTTP_headers
Una de mis referencias favoritas de OWASP es la explicación de las secuencias de comandos en sitios cruzados porque, si bien hay una gran cantidad de vectores de ataque XSS, ¡el seguimiento de algunas reglas puede defenderse en gran medida de la mayoría de ellos!
Uno de los pasos más importantes es sanear cualquier entrada del usuario antes de que se procese y / o se devuelva al navegador. PHP tiene algunas funciones de " filter " que se pueden usar.
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 here .
También querrá probar su sitio. Puedo recomendar el complemento de Firefox XSS Me .
Utilice htmlspecialchars
en PHP
. En HTML intente evitar usar:
element.innerHTML = “…”; element.outerHTML = “…”; document.write(…); document.writeln(…);
donde var
es controlado por el usuario .
Obviamente, también intente evitar eval(var)
, si tiene que usar alguno de ellos, intente que JS los escape, HTML los escape y es posible que tenga que hacer algo más, pero para lo básico, esto debería ser suficiente.
Publicación cruzada de esto como una referencia consolidada de la versión beta de la documentación de SO que se está desconectando.
Problema
Las secuencias de comandos entre sitios son 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 publica directamente en una página web. Si la entrada incluye HTML o JavaScript, se puede ejecutar un código remoto cuando el cliente web representa este contenido.
Por ejemplo, si un tercero incluye un archivo JavaScript:
// http://example.com/runme.js
document.write("I''m running");
Y una aplicación PHP emite directamente una cadena que se le pasa:
<?php
echo ''<div>'' . $_GET[''input''] . ''</div>'';
Si un parámetro GET sin marcar contiene <script src="http://example.com/runme.js"></script>
, la salida del script PHP será:
<div><script src="http://example.com/runme.js"></script></div>
El JavaScript de terceros se ejecutará 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. Cuando emita cualquiera de estos valores, escápelos 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 dependiendo del contexto.
Funciones de filtro
Las funciones de filtro de PHP permiten que los datos de entrada al script php se filter o validated de muchas maneras . Son útiles al guardar o enviar datos de 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:
<?php
echo ''<div>'' . htmlspecialchars($_GET[''input'']) . ''</div>'';
// or
echo ''<div>'' . filter_input(INPUT_GET, ''input'', FILTER_SANITIZE_SPECIAL_CHARS) . ''</div>'';
Sería de salida:
<div><script src="http://example.com/runme.js"></script></div>
Todo lo que esté dentro de la etiqueta <div>
no será interpretado como una etiqueta de JavaScript por el navegador, sino como un simple nodo de texto. El usuario verá con seguridad:
<script src="http://example.com/runme.js"></script>
Codificación URL
Cuando se genera una URL generada dinámicamente, PHP proporciona la función urlencode
para urlencode
con seguridad URL válidas. Entonces, por ejemplo, si un usuario puede ingresar datos que se convierten en parte de otro parámetro GET:
<?php
$input = urlencode($_GET[''input'']);
// or
$input = filter_input(INPUT_GET, ''input'', FILTER_SANITIZE_URL);
echo ''<a href="http://example.com/page?input="'' . $input . ''">Link</a>'';
Cualquier entrada maliciosa se convertirá en un parámetro de URL codificada.
Usando bibliotecas externas especializadas o listas de OWASP AntiSamy
A veces deseará enviar HTML u otro tipo de entradas de código. Deberá mantener una lista de palabras autorizadas (lista blanca) y no autorizada (lista negra).
Puede descargar las listas estándar disponibles en el sitio web de OWASP AntiSamy . Cada lista es apta para un tipo específico de interacción (ebay api, tinyMCE, etc ...). Y es de código abierto.
Existen bibliotecas para filtrar HTML y prevenir ataques XSS en el caso general y que funcionan al menos tan bien como las listas de AntiSamy con un uso muy fácil. Por ejemplo tienes htmlpurifier.org
Básicamente, debe usar la función htmlspecialchars()
siempre que desee mostrar algo en el navegador que proviene de la entrada del usuario.
La forma correcta de usar esta función es algo como esto:
echo htmlspecialchars($string, ENT_QUOTES, ''UTF-8'');
Google Code University también tiene estos videos muy educativos sobre seguridad web:
<?php
function xss_clean($data)
{
// Fix &entity/n;
$data = str_replace(array(''&'',''<'',''>''), array(''&amp;'',''&lt;'',''&gt;''), $data);
$data = preg_replace(''/(&#*/w+)[/x00-/x20]+;/u'', ''$1;'', $data);
$data = preg_replace(''/(&#x*[0-9A-F]+);*/iu'', ''$1;'', $data);
$data = html_entity_decode($data, ENT_COMPAT, ''UTF-8'');
// Remove any attribute starting with "on" or xmlns
$data = preg_replace(''#(<[^>]+?[/x00-/x20"/'])(?:on|xmlns)[^>]*+>#iu'', ''$1>'', $data);
// Remove javascript: and vbscript: protocols
$data = preg_replace(''#([a-z]*)[/x00-/x20]*=[/x00-/x20]*([`/'"]*)[/x00-/x20]*j[/x00-/x20]*a[/x00-/x20]*v[/x00-/x20]*a[/x00-/x20]*s[/x00-/x20]*c[/x00-/x20]*r[/x00-/x20]*i[/x00-/x20]*p[/x00-/x20]*t[/x00-/x20]*:#iu'', ''$1=$2nojavascript...'', $data);
$data = preg_replace(''#([a-z]*)[/x00-/x20]*=([/'"]*)[/x00-/x20]*v[/x00-/x20]*b[/x00-/x20]*s[/x00-/x20]*c[/x00-/x20]*r[/x00-/x20]*i[/x00-/x20]*p[/x00-/x20]*t[/x00-/x20]*:#iu'', ''$1=$2novbscript...'', $data);
$data = preg_replace(''#([a-z]*)[/x00-/x20]*=([/'"]*)[/x00-/x20]*-moz-binding[/x00-/x20]*:#u'', ''$1=$2nomozbinding...'', $data);
// Only works in IE: <span style="width: expression(alert(''Ping!''));"></span>
$data = preg_replace(''#(<[^>]+?)style[/x00-/x20]*=[/x00-/x20]*[`/'"]*.*?expression[/x00-/x20]*/([^>]*+>#i'', ''$1>'', $data);
$data = preg_replace(''#(<[^>]+?)style[/x00-/x20]*=[/x00-/x20]*[`/'"]*.*?behaviour[/x00-/x20]*/([^>]*+>#i'', ''$1>'', $data);
$data = preg_replace(''#(<[^>]+?)style[/x00-/x20]*=[/x00-/x20]*[`/'"]*.*?s[/x00-/x20]*c[/x00-/x20]*r[/x00-/x20]*i[/x00-/x20]*p[/x00-/x20]*t[/x00-/x20]*:*[^>]*+>#iu'', ''$1>'', $data);
// Remove namespaced elements (we do not need them)
$data = preg_replace(''#</*/w+:/w[^>]*+>#i'', '''', $data);
do
{
// Remove really unwanted tags
$old_data = $data;
$data = preg_replace(''#</*(?:applet|b(?:ase|gsound|link)|embed|frame(?:set)?|i(?:frame|layer)|l(?:ayer|ink)|meta|object|s(?:cript|tyle)|title|xml)[^>]*+>#i'', '''', $data);
}
while ($old_data !== $data);
// we are done...
return $data;
}