php - seguridad - strip_tags
¿Cuáles son las mejores prácticas para evitar ataques xss en un sitio PHP? (20)
Tengo PHP configurado para que las comillas mágicas estén activadas y los registros globales estén desactivados.
Hago lo mejor que puedo para llamar siempre a htmlentities () para cualquier cosa que estoy generando y que se deriva de la entrada del usuario.
También de vez en cuando busco en mi base de datos cosas comunes usadas en xss adjunto como ...
<script
¿Qué más debería estar haciendo y cómo puedo asegurarme de que las cosas que estoy tratando de hacer siempre se hagan?
rikh Escribe:
Hago lo mejor que puedo para llamar siempre a htmlentities () para cualquier cosa que estoy generando y que se deriva de la entrada del usuario.
Consulte el ensayo de Joel sobre Cómo hacer que Code Look Wrong busque ayuda con esto
"Citas mágicas" es un remedio paliativo para algunos de los peores defectos XSS que funciona escapando todo en la entrada, algo que está mal por diseño. El único caso donde uno querría usarlo es cuando absolutamente debe usar una aplicación PHP existente que se sabe que se escribió descuidadamente con respecto a XSS. (En este caso, usted está en un problema serio incluso con "citas mágicas"). Al desarrollar su propia aplicación, debe desactivar las "comillas mágicas" y seguir las prácticas seguras de XSS.
XSS, una vulnerabilidad de secuencias de comandos entre sitios, ocurre cuando una aplicación incluye cadenas de fuentes externas (entradas del usuario, extraídas de otros sitios web, etc.) en su [X] HTML, CSS, ECMAscript u otra salida analizada por el navegador sin un escape adecuado, con la esperanza que los caracteres especiales como menos que (en [X] HTML), comillas simples o dobles (ECMAscript) nunca aparecerán. La solución adecuada es escaparse siempre de las cadenas de acuerdo con las reglas del lenguaje de salida: usando entidades en [X] HTML, barras invertidas en ECMAscript, etc.
Debido a que puede ser difícil hacer un seguimiento de lo que no es de confianza y se tiene que escapar, es una buena idea escapar siempre de todo lo que sea 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), etc. De esta forma, una conversión implícita directa de "cadena" a "cadena HTML" sería imposible, y la única forma en que una cadena podría convertirse en una marca HTML es pasarla a través de una función de escape.
"Registrar globales", aunque deshabilitarlo definitivamente es una buena idea, se trata de un problema completamente diferente de XSS.
Al menos debe validar todos los datos que entran en la base de datos. Y trate de validar todos los datos que salen de la base de datos también.
mysql_real_escape_string es bueno para evitar la inyección SQL, pero XSS es más complicado. ¡Debes preg_match, stip_tags o htmlentities donde sea posible!
Confío en PHPTAL para eso.
A diferencia de Smarty y PHP simple, escapa todo el resultado por defecto. Esta es una gran victoria para la seguridad, ya que su sitio no se volverá vulnerable si olvida htmlspecialchars()
o |escape
algún lugar.
XSS es un ataque específico de HTML, por lo que la salida HTML es el lugar correcto para evitarlo. No debe intentar prefiltrar datos en la base de datos, ya que podría necesitar generar datos en otro medio que no acepte HTML, pero que tiene sus propios riesgos.
Cree cualquier cookie de sesión (o todas las cookies) que use HttpOnly. La mayoría de los navegadores ocultan el valor de la cookie de JavaScript en ese caso. El usuario aún puede copiar cookies de forma manual, pero esto ayuda a evitar el acceso directo al script. tuvo este problema durante beta.
Esto no es una solución, solo otro ladrillo en la pared
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 un caché de código operativo como APC. Debería usar esto en cualquier lugar donde el contenido que no es de confianza se emita en la pantalla. Es mucho más completo que htmlentities, htmlspecialchars, filter_input, filter_var, strip_tags, etc.
Encuentro que la mejor manera es usar una clase que te permita vincular tu código para que nunca tengas que preocuparte por escaparte manualmente de tus datos.
Es difícil implementar una inyección de inyecciones sql / xss completas en un sitio que no cause falsas alarmas. En un CMS, el usuario final puede querer usar <script>
u <object>
que enlaza con elementos de otro sitio.
Recomiendo que todos los usuarios instalen FireFox con NoScript ;-)
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 estén permitidos los enlaces de javascript:
; estos ejecutarían un script tan pronto como el usuario haga clic en el enlace.
Esta es una gran pregunta.
En primer lugar, no escape el texto en la entrada, excepto para que sea seguro para el almacenamiento (como, por ejemplo, ponerlo en una base de datos). La razón de esto es que desea mantener lo que se ingresó para que pueda presentarlo de manera diferente en diferentes lugares y lugares. Hacer cambios aquí puede comprometer su presentación posterior.
Cuando vaya a presentar su filtro de datos, lo que no debería estar allí. Por ejemplo, si no hay una razón para que JavaScript esté allí, búscalo y quítalo. 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ásales ideas o htmlspecialchars para cambiar lo que está ahí para los personajes ascii. Haga esto en función del contexto y de lo que desea obtener.
También, sugiero que desactive las cotizaciones mágicas. Se ha eliminado de PHP 6 y se considera una mala práctica para usarlo. Detalles en http://us3.php.net/magic_quotes
Para obtener más detalles, consulte http://ha.ckers.org/xss.html
Esta no es una respuesta completa, pero con la esperanza de ayudarlo a comenzar.
Hay muchas maneras de hacer XSS (Ver http://ha.ckers.org/xss.html ) y es muy difícil de atrapar.
Yo personalmente delego esto al marco actual que estoy usando (Code Igniter por ejemplo). Si bien no es perfecto, podría atrapar más de lo que hacen mis rutinas hechas a mano.
La entrada de escape no es lo mejor que puede hacer para una prevención exitosa de XSS. También la salida debe ser escapada. Si utiliza el motor de plantillas Smarty, puede usar |escape:''htmlall''
modificador |escape:''htmlall''
para convertir todos los caracteres sensibles en entidades HTML (utilizo el modificador own |e
que es un alias del anterior).
Mi enfoque para la seguridad de entrada / salida es:
- no se modificó la entrada del usuario de la tienda (no se escapó HTML en la entrada, solo se realizó el escaneado con DB mediante declaraciones preparadas por PDO)
- escape en la salida, dependiendo del formato de salida que use (por ejemplo, HTML y JSON necesitan diferentes reglas de escape)
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
Personalmente, inhabilitaría magic_quotes. En PHP5 + está deshabilitado por defecto y es mejor codificar como si no estuviera allí, ya que no escapa de todo y se eliminará de PHP6.
A continuación, dependiendo del tipo de datos del usuario que está filtrando, se dictará qué hacer a continuación, por ejemplo, si solo se trata de texto, por ejemplo, un nombre, strip_tags(trim(stripslashes()));
o para verificar los rangos usa expresiones regulares.
Si espera un cierto rango de valores, cree una matriz de valores válidos y solo permita que esos valores in_array($userData, array(...))
).
Si está comprobando los números, use is_numeric para imponer números enteros o enviarlos a un tipo específico, lo que debería evitar que las personas que intentan enviar cadenas lo reemplacen.
Si tiene PHP5.2 +, considere buscar en 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 tiene que manejar HTML, debería considerar algo como PHP Input Filter o HTML Purifier . HTML Purifier también validará HTML para la conformidad. No estoy seguro si el filtro de entrada aún se está desarrollando. Ambos le permitirán definir un conjunto de etiquetas que se pueden usar y qué atributos están permitidos.
Independientemente de lo que decida, recuerde siempre, nunca confíe en nada que ingrese a su script PHP desde un usuario (¡incluido usted mismo!).
Si le preocupan los ataques XSS, codificar sus cadenas de salida en HTML es la solución. Si recuerda codificar cada carácter de salida en formato HTML, no hay forma de ejecutar un ataque XSS exitoso.
Leer más: Desinfección de datos de usuario: cómo y dónde hacerlo
Soy de la opinión de que uno no debe escapar de nada durante la entrada, solo en la salida. Como (la mayoría de las veces) no puede suponer 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 diferentes escapes (de lo contrario, un usuario malintencionado podría reescribir sus encabezados de correo electrónico).
En otras palabras, solo puede escapar en el último momento en que los datos "salgan" de su aplicación:
- Artículo de lista
- Escribir en el archivo XML, escape para XML
- Escribir en DB, escape (para ese DBMS en particular)
- Escribir correo electrónico, escapar de correos electrónicos
- etc
Para abreviar:
- No sabes a dónde van tus datos
- Los datos en realidad podrían terminar en más de un lugar, necesitando diferentes mecanismos de escape PERO NO AMBOS
- Los datos escapados para el objetivo equivocado realmente no son agradables. (Por ejemplo, recibir un correo electrónico con el asunto "Ir a la barra de Tommy").
Esp # 3 ocurrirá si escapas los datos en la capa de entrada (o si necesitas escapar de nuevo, etc.).
PD: voy a secundar el consejo de no usar magic_quotes, ¡eso es pura maldad!
Todas estas respuestas son excelentes, pero fundamentalmente, la solución para XSS será dejar de generar documentos HTML mediante la manipulación de cadenas.
El filtrado de entrada siempre es una buena idea para cualquier aplicación.
Escapar tu salida usando htmlentities () y amigos debería funcionar siempre que se use correctamente, pero este es el equivalente HTML de crear una consulta SQL concatenando cadenas con mysql_real_escape_string ($ var) - debería funcionar, pero menos cosas pueden validar tu 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, tal vez usando una interfaz estándar como DOM, y luego usar una biblioteca (como libxml) para manejar la serialización a XHTML / HTML / etc. Por supuesto, estamos muy lejos de ser popular y lo suficientemente rápido, pero mientras tanto tenemos que construir nuestros documentos HTML a través de operaciones de cadenas, y eso es inherentemente más arriesgado.
Use una biblioteca de sanitización de entrada de usuario existente para limpiar toda la entrada de usuario. A menos que ponga mucho esfuerzo en ello, implementarlo usted mismo nunca funcionará tan bien.
Biblioteca de plantillas. O al menos, eso es lo que deben hacer las bibliotecas de plantillas. Para evitar XSS, todas las salidas deben estar codificadas. Esta no es la tarea de la lógica principal de aplicación / control, solo debe ser manejada por los métodos de salida.
Si rocías htmlentities () a través de tu código, el diseño general es incorrecto. Y como sugieres, es posible que te pierdas uno o dos lugares. Es por eso que la única solución es la rigurosa codificación html -> cuando los vars de salida se escriben 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, localización, validación html ni nada importante. ¿Tal vez alguien más conoce una biblioteca de plantillas adecuada para php?
- No confíes en la entrada del usuario
- Escape de toda la salida de texto libre
- No use magic_quotes; ver si hay una variante específica de DBMS o usar PDO
- Considere usar cookies HTTP-only cuando sea posible para evitar que cualquier script malicioso pueda secuestrar una sesión