Cuáles son las mejores prácticas para evitar ataques xss en un sitio PHP


He configurado PHP para que las comillas mágicas estén activadas y los globales de registro estén desactivados.

Hago todo lo posible para llamar siempre a htmlentities() para cualquier cosa que esté emitiendo que se derive de la entrada del usuario.

También ocasionalmente seach mi base de datos para cosas comunes que se utilizan en xss adjuntos como...

<script

Qué más debería estar haciendo y cómo puedo asegurarme de que las cosas que estoy tratando de hacer estén siempre hechas.

Author: Rik Heywood, 2008-09-16

20 answers

Escapar de la entrada no es lo mejor que puede hacer para una prevención XSS exitosa. También salida debe ser escapado. Si usa Smarty template engine, puede usar el modificador |escape:'htmlall' para convertir todos los caracteres sensibles a entidades HTML (yo uso el modificador propio |e que es alias del anterior).

Mi enfoque para la seguridad de entrada / salida es:

  • almacenar la entrada del usuario no modificada (no hay escape de HTML en la entrada, solo el escape de DB-aware se realiza a través de instrucciones preparadas por PDO)
  • escape en la salida, dependiendo del formato de salida que utilice (por ejemplo, HTML y JSON necesitan diferentes reglas de escape)
 58
Author: Michał Rudnicki,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-16 11:41:23

Soy de la opinión de que uno no debe escapar de nada durante la entrada, solo en la salida. Dado que (la mayoría de las veces) no puede asumir que sabe a dónde van esos datos. Por ejemplo, si tiene un formulario que toma datos que luego aparecen en un correo electrónico que envía, necesita un escape diferente (de lo contrario, un usuario malicioso podría reescribir sus encabezados de correo electrónico).

En otras palabras, solo puede escapar en el último momento en que los datos están "saliendo" de su aplicación:

  • Lista elemento
  • Escribir en un archivo XML, escape para XML
  • Escribir en DB, escape (para ese DBMS en particular)
  • Escribir correo electrónico, escape para correos electrónicos
  • etc

Para ir corto:

  1. No sabes a dónde van tus datos
  2. Los datos podrían terminar en más de un lugar, necesitando diferentes mecanismos de escape, PERO NO AMBOS
  3. Los datos escapados para el objetivo equivocado no son realmente agradables. (Por ejemplo, obtener un correo electrónico con el asunto "Ir a Tommy's Bar".)

Esp #3 se producirá si escapa datos en la capa de entrada (o necesita des-escapar de nuevo, etc.).

PD: Voy a segundo el consejo para no usar magic_quotes, esos son pura maldad!

 18
Author: Jilles,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-16 21:32:29

Hay muchas maneras de hacer XSS (Ver http://ha.ckers.org/xss.html ) y es muy difícil de atrapar.

Personalmente delego esto al framework actual que estoy usando (Code Igniter por ejemplo). Si bien no es perfecto, podría atrapar más de lo que mis rutinas hechas a mano nunca hacen.

 12
Author: Christian Studer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-16 11:38:17

Esta es una gran pregunta.

Primero, no escape el texto en la entrada, excepto para hacerlo seguro para el almacenamiento (como ser puesto en una base de datos). La razón de esto es que desea mantener lo que se introdujo para que pueda presentarlo contextualmente de diferentes maneras y lugares. Hacer cambios aquí puede comprometer su presentación posterior.

Cuando vayas a presentar tus datos filtra lo que no debería estar allí. Por ejemplo, si no hay una razón para que javascript esté allí búsqueda y quitar se. Una manera fácil de hacerlo es usar la función strip_tags y solo presentar las etiquetas html que está permitiendo.

A continuación, toma lo que tienes y pásalo pensado htmlentities o htmlspecialchars para cambiar lo que hay a caracteres ascii. Haz esto en función del contexto y de lo que quieres sacar.

También sugiero desactivar las Comillas Mágicas. Se ha eliminado de PHP 6 y se considera una mala práctica usarlo. Detalles en http://us3.php.net/magic_quotes

Para más detalles echa un vistazo a http://ha.ckers.org/xss.html

Esta no es una respuesta completa, pero espero que sea suficiente para ayudarte a empezar.

 10
Author: Matt Farina,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-16 12:13:45

Rikh Escribe:

Hago todo lo posible para llamar siempre a htmlentities() para cualquier cosa que esté emitiendo que se derive de la entrada del usuario.

Vea el ensayo de Joel sobre Hacer que el Código Parezca incorrecto para obtener ayuda con esto

 7
Author: Mason,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-16 19:13:19

Confío en PHPTAL para eso.

A diferencia de Smarty y PHP simple, escapa toda la salida por defecto. Esta es una gran victoria para la seguridad, porque su sitio no se volverá vurnelable si olvida htmlspecialchars() o |escape en algún lugar.

XSS es un ataque específico de HTML, por lo que la salida HTML es el lugar correcto para prevenirlo. No debe intentar pre-filtrar datos en la base de datos, porque podría necesitar datos de salida a otro medio que no acepta HTML, pero tiene sus propios riesgos.

 4
Author: Kornel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-25 21:07:32

Biblioteca de plantillas. O al menos, eso es lo que deberían hacer las bibliotecas de plantillas. Para evitar XSS toda la salida debe ser codificada. Esta no es la tarea de la aplicación principal / lógica de control, solo debe ser manejada por los métodos de salida.

Si espolvorea htmlentities() a través de su código, el diseño general es incorrecto. Y como sugieres, podrías perder uno o dos puntos. Es por eso que la única solución es la codificación html rigurosa -> cuando escrito en una secuencia html/xml.

Desafortunadamente, la mayoría de las bibliotecas de plantillas php solo agregan su propia sintaxis de plantilla, pero no se preocupan por la codificación de salida, o la localización, o la validación html, o cualquier cosa importante. Tal vez alguien más conoce una biblioteca de plantillas adecuada para php?

 4
Author: user319490,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-18 02:01:08

Escapar toda la entrada del usuario es suficiente para la mayoría de los sitios. También asegúrese de que los ID de sesión no terminen en la URL para que no puedan ser robados del enlace Referer a otro sitio. Además, si permite que sus usuarios envíen enlaces, asegúrese de que no se permitan enlaces de protocolo javascript:; estos ejecutarían un script tan pronto como el usuario haga clic en el enlace.

 2
Author: Konrad Rudolph,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-16 11:24:39

Si le preocupan los ataques XSS, la solución es codificar las cadenas de salida a HTML. Si recuerda codificar cada carácter de salida al formato HTML, no hay manera de ejecutar un ataque XSS exitoso.

Leer más: Desinfectar los datos del usuario: Cómo y dónde hacerlo

 2
Author: Niyaz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-16 11:40:58

Personalmente, desactivaría magic_quotes. En PHP5 + está desactivado por defecto y es mejor codificar como si no estuviera allí en absoluto, ya que no escapa de todo y se eliminará de PHP6.

Luego, dependiendo del tipo de datos de usuario que esté filtrando, dictará qué hacer a continuación, por ejemplo, si es solo texto, por ejemplo, un nombre, entonces strip_tags(trim(stripslashes())); o para verificar rangos use expresiones regulares.

Si espera un cierto rango de valores, cree una matriz de los valores válidos y solo permita esos valores a través de (in_array($userData, array(...))).

Si está comprobando números use is_numeric para imponer números enteros o cast a un tipo específico, eso debería evitar que las personas intenten enviar cadenas en lugar.

Si tiene PHP5.2+, considere mirar filter() y hacer uso de esa extensión que puede filtrar varios tipos de datos, incluidas las direcciones de correo electrónico. La documentación no es particularmente buena, pero está mejorando.

Si tienes que manejar HTML entonces deberías considere algo como PHP Input Filter o HTML Purifier. HTML Purifier también validará HTML para la conformidad. No estoy seguro de si el Filtro de entrada todavía se está desarrollando. Ambos le permitirán definir un conjunto de etiquetas que se pueden usar y qué atributos están permitidos.

Sea lo que sea que decidas, siempre recuerda, nunca confíes en nada que entre en tu script PHP de un usuario (¡incluyéndote a ti mismo!).

 2
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-16 19:09:23

Todas estas respuestas son geniales, pero fundamentalmente, la solución a XSS será dejar de generar documentos HTML mediante la manipulación de cadenas.

Filtrar la entrada siempre es una buena idea para cualquier aplicación.

Escapar de su salida usando htmlentities () y amigos debería funcionar siempre y cuando se use correctamente, pero este es el equivalente HTML de crear una consulta SQL concatenando cadenas con mysql_real_escape_string (var var) - debería funcionar, pero menos cosas pueden validar su trabajo, por así decirlo, en comparación con un enfoque como el uso de consultas parametrizadas.

La solución a largo plazo debería ser que las aplicaciones construyan la página internamente, quizás usando una interfaz estándar como el DOM, y luego usar una biblioteca (como libxml) para manejar la serialización a XHTML/HTML/etc. Por supuesto, estamos muy lejos de que eso sea popular y lo suficientemente rápido, pero mientras tanto tenemos que construir nuestros documentos HTML a través de operaciones de cadena, y eso es inherentemente más arriesgado.

 2
Author: Daniel Papasian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-16 21:24:32

Me parece que el uso de esta función ayuda a eliminar una gran cantidad de posibles ataques xss: http://www.codebelay.com/killxss.phps

 2
Author: barce,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-16 21:35:01

"Magic quotes" es un remedio paliativo para algunos de los peores defectos de XSS que funciona escapando todo en la entrada, algo que está mal por diseño. El único caso en el que uno querría usarlo es cuando absolutamente debe usar una aplicación PHP existente que se sabe que está escrita descuidadamente con respecto a XSS. (En este caso estás en un serio problema incluso con "citas mágicas".) Al desarrollar su propia aplicación, debe desactivar "comillas mágicas" y seguir las prácticas de XSS-safe en su lugar.

XSS, una vulnerabilidad de scripting entre sitios, ocurre cuando una aplicación incluye cadenas de fuentes externas (entrada de usuario, recuperadas de otros sitios web, etc.) en su [X]HTML, CSS, ECMAScript u otro resultado analizado por el navegador sin escaparse adecuadamente, con la esperanza de que nunca aparezcan caracteres especiales como menos que (en [X]HTML), comillas simples o dobles (ECMAScript). La solución adecuada para ello es siempre escapar cadenas de acuerdo con las reglas del lenguaje de salida: [X]HTML, barras invertidas en ECMAScript, etc.

Debido a que puede ser difícil realizar un seguimiento de lo que no es de confianza y tiene que ser escapado, es una buena idea siempre escapar de todo lo que es una "cadena de texto" en lugar de "texto con marcado" en un lenguaje como HTML. Algunos entornos de programación lo hacen más fácil al introducir varios tipos de cadenas incompatibles: "cadena" (texto normal), "cadena HTML" (marcado HTML) y así sucesivamente. De esa manera, una conversión directa implícita de "cadena" a "cadena HTML" sería imposible, y la única forma en que una cadena podría convertirse en marcado HTML es pasándola a través de una función de escape.

"Register globals", aunque desactivarlo es definitivamente una buena idea, trata con un problema completamente diferente de XSS.

 2
Author: Alexey Feldgendler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-11 15:48:44

Hacer que cualquier cookie de sesión (o todas las cookies) que utilice HttpOnly. La mayoría de los navegadores ocultarán el valor de la cookie de JavaScript en ese caso. El usuario todavía podría copiar manualmente las cookies, pero esto ayuda a evitar el acceso directo al script. StackOverflow tuvo este problema durante la beta.

Esto no es una solución, solo otro ladrillo en la pared

 1
Author: basszero,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-16 12:17:07
  • No confíes en la entrada del usuario
  • Escape all free-text output
  • No use magic_quotes; vea si hay una variante DBMS-specfic, o use PDO
  • Considere usar cookies solo HTTP cuando sea posible para evitar que cualquier script malicioso pueda secuestrar una sesión
 1
Author: Rob,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-16 21:28:06

Al menos debe validar todos los datos que entran en la base de datos. Y tratar de validar todos los datos que salen de la base de datos también.

Mysql_real_escape_string es bueno para prevenir la inyección SQL, pero XSS es más complicado. Usted debe preg_match, stip_tags, o htmlentities cuando sea posible!

 1
Author: Abeon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-19 23:54:53

El mejor método actual para prevenir XSS en una aplicación PHP es HTML Purifier (http://htmlpurifier.org/). Un inconveniente menor es que es una biblioteca bastante grande y se usa mejor con una caché de código OP como APC. Usted podría utilizar esto en cualquier lugar donde el contenido no confiable está siendo enviado a la pantalla. Es mucho más completo que htmlentities, htmlspecialchars, filter_input, filter_var, strip_tags, etc.

 1
Author: Night Owl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-04-24 18:36:55

Utilice una biblioteca de desinfección de entrada de usuario existente para limpiar toda la entrada de usuario. A menos que ponga un lote de esfuerzo en él, implementarlo usted mismo nunca funcionará tan bien.

 0
Author: dbr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-16 12:04:44

Creo que la mejor manera es usar una clase que le permita enlazar su código para que nunca tenga que preocuparse por escapar manualmente sus datos.

 0
Author: Darren22,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2008-09-16 21:37:34

Es difícil implementar una prevención de inyección sql/inyección xss completa en un sitio que no cause falsas alarmas. En un CMS, el usuario final puede usar <script> o <object> que enlaza a elementos de otro sitio.

Recomiendo que todos los usuarios instalen FireFox con NoScript; -)

 -1
Author: Adam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-12-17 11:51:31