php - remove - strip_tags wordpress
¿Cuál es la forma correcta de detectar si las entradas de cadena contienen HTML o no? (13)
Ciertamente no soy un experto en seguridad, pero por lo que reúno algo así como su sugerencia
if (htmlspecialchars($data, ENT_NOQUOTES, ''UTF-8'') === $data)
debería funcionar para evitar que transmitas cadenas contaminadas, dado que tienes tu codificación allí mismo.
XSS ataques XSS que no requieren ''<'' o ''>'' dependen de la cadena que se maneja en un bloque de JavaScript justo ahí, lo cual, por la forma en que leo su pregunta, no es lo que le preocupa en esta situación.
Al recibir la entrada del usuario en formularios, quiero detectar si campos como "nombre de usuario" o "dirección" no contienen marcas que tengan un significado especial en XML (fuentes RSS) o (X) HTML (cuando se muestran).
Entonces, ¿cuál de estas es la forma correcta de detectar si la entrada ingresada no contiene ningún carácter especial en el contexto HTML y XML?
if (mb_strpos($data, ''<'') === FALSE AND mb_strpos($data, ''>'') === FALSE)
o
if (htmlspecialchars($data, ENT_NOQUOTES, ''UTF-8'') === $data)
o
if (preg_match("/[^/p{L}/-.'']/u", $text)) // problem: also caches symbols
¿Me he perdido algo más, como secuencias de bytes u otras formas complicadas de obtener etiquetas de marcado sobre cosas como "javascript:"? Por lo que sé, todos los ataques XSS y CSFR requieren <
o >
alrededor de los valores para que el navegador ejecute el código (bueno al menos desde Internet Explorer 6 o posterior): ¿es correcto?
No estoy buscando algo para reducir o filtrar la entrada. Solo quiero localizar secuencias de caracteres peligrosos cuando se usan en contexto XML o HTML. ( strip_tags()
es terriblemente inseguro. Como dice el manual, no verifica si hay HTML mal formado.)
Actualizar
Creo que necesito aclarar que hay mucha gente que confunde esta pregunta con una pregunta sobre seguridad básica a través de "escapar" o "filtrar" personajes peligrosos. Esta no es la pregunta, y la mayoría de las respuestas simples dadas no resolverían ese problema de todos modos.
Actualización 2: Ejemplo
- El usuario envía la entrada
-
if (mb_strpos($data, ''<'') === FALSE AND mb_strpos($data, ''>'') === FALSE)
- Lo guardo
Ahora que los datos están en mi aplicación, hago dos cosas con ella: 1) mostrar en un formato como HTML - o 2) mostrar dentro de un elemento de formato para editar.
El primero es seguro en contexto XML y HTML
<h2><?php print $input; ?></h2>''
<h2><?php print $input; ?></h2>''
<xml><item><?php print $input; ?></item></xml>
<xml><item><?php print $input; ?></item></xml>
La segunda forma es más peligrosa, pero aún así debería ser segura:
<input value="<?php print htmlspecialchars($input, ENT_QUOTES, ''UTF-8'');?>">
Actualización 3: Código de trabajo
Puede descargar la esencia que creé y ejecutar el código como una respuesta de texto o HTML para ver de lo que estoy hablando. Esta simple verificación pasa la http://ha.ckers.org XSS Cheat Sheet , y no puedo encontrar nada que la haga pensar. (Estoy ignorando Internet Explorer 6 y abajo).
Empecé otra recompensa para premiar a alguien que puede mostrar un problema con este enfoque o una debilidad en su implementación.
Actualización 4: Pregunta a un DOM
Es el DOM lo que queremos proteger, entonces ¿por qué no solo preguntarlo? La respuesta de Timur lleva a esto:
function not_markup($string)
{
libxml_use_internal_errors(true);
if ($xml = simplexml_load_string("<root>$string</root>"))
{
return $xml->children()->count() === 0;
}
}
if (not_markup($_POST[''title''])) ...
Creo que respondiste tu propia pregunta. La función htmlspecialchars()
hace exactamente lo que necesita, pero no debe usarla hasta que escriba la entrada del usuario a una página. Para almacenarlo en una base de datos hay otras funciones, como mysqli_real_escape_string()
.
Como regla general, uno puede decir que debe escapar de la entrada del usuario solo cuando sea necesario, para el sistema objetivo dado:
- Escaparse de la entrada del usuario a menudo significa una pérdida de los datos originales, y diferentes sistemas de destino (salida HTML / SQL / ejecución) necesitan diferentes escapes. Incluso pueden entrar en conflicto entre ellos.
- Tienes que escapar de los datos para el propósito dado de todos modos, siempre . No debe confiar incluso en las entradas de su base de datos. Por lo tanto, escaparse cuando lee de la entrada del usuario no tiene ninguna gran ventaja, pero el doble escape puede generar datos no válidos.
En contraste con escapar, validar el contenido es algo bueno de hacer temprano. Si espera un número entero, solo acepte números enteros, de lo contrario, rechace la entrada del usuario.
En un comentario anterior, escribiste:
Simplemente, detenga que el navegador trate la cadena como marcado.
Este es un problema completamente diferente al que está en el título. El enfoque en el título suele ser incorrecto. La eliminación de etiquetas simplemente altera la entrada y puede conducir a la pérdida de datos. ¿Has intentado alguna vez hablar sobre HTML en un blog que elimina etiquetas? Frustrante.
La solución que suele ser la correcta es hacer lo que dice en su comentario, para evitar que el navegador trate la cadena como marcado. Esto - literalmente tomado - no es posible. Lo que haces en cambio es codificar el contenido como HTML.
Considere los siguientes datos:
<strong>Test</strong>
Ahora, puedes ver esta de dos maneras. Puede verlo como datos literales, una secuencia de caracteres. Puedes verlo como HTML - marcado que incluye enfáticamente el texto.
Si acaba de volcarlo en un documento HTML, lo está tratando como HTML. No puede tratarlo como datos literales en ese contexto. Lo que necesita es HTML que generará los datos literales. Debe codificarlo como HTML.
Tu problema no es que tengas demasiado HTML, es que tienes muy poco. Cuando imprime <
, está enviando datos sin procesar en un contexto HTML. Necesita convertirlo a <
, que es la representación HTML de esos datos antes de su salida.
PHP ofrece algunas opciones diferentes para hacer esto. El más directo es usar htmlspecialchars()
para convertirlo en HTML, y luego nl2br()
para convertir los saltos de línea en elementos <br>
.
La forma correcta de detectar si las entradas de cadena contienen etiquetas HTML, o cualquier otra marca que tenga un significado especial en XML o (X) HTML cuando se muestra (que no sea una entidad) es simplemente
if (mb_strpos($data, ''<'') === FALSE AND mb_strpos($data, ''>'') === FALSE)
¡Estás en lo correcto! Todos los ataques XSS y CSFR requieren <o> alrededor de los valores para que el navegador ejecute el código (al menos desde IE6 +).
Teniendo en cuenta el contexto de salida dado, esto es suficiente para mostrar de forma segura en un formato como HTML:
<h2><?php print $input; ?></h2> <xml><item><?php print $input; ?></item></xml>
Por supuesto, si tenemos alguna entidad en la entrada, como á
, un navegador no lo á
como á
, pero como á
, a menos que usemos una función como htmlspecialchars
al hacer la salida. En este caso, incluso el <
y >
también sería seguro.
En el caso de utilizar la entrada de cadena como el valor de un atributo, la seguridad depende del atributo.
Si el atributo es un valor de entrada , debemos citarlo y usar una función como htmlspecialchars
para recuperar el mismo contenido para su edición.
<input value="<?php print htmlspecialchars($input, ENT_QUOTES, ''UTF-8'');?>">
De nuevo, incluso los personajes <
y >
estarían seguros aquí.
Podemos concluir que no tenemos que hacer ningún tipo de detección y rechazo de la entrada, si siempre usaremos htmlspecialchars
para dar salida, y nuestro contexto siempre se ajustará a los casos anteriores (o igualmente seguros).
[Y también tenemos varias maneras de almacenarlo de forma segura en la base de datos, evitando exploits SQL.]
¿Qué pasa si el usuario quiere que su "nombre de usuario" sea & is not an &
& is not an &
? No contiene <
ni >
... ¿lo detectaremos y rechazaremos? ¿Lo aceptaremos? ¿Cómo lo mostraremos? (¡Esta entrada da resultados interesantes en la nueva recompensa!)
Finalmente, si nuestro contexto se expande, y usaremos la entrada de cadena como ancla href , entonces todo nuestro enfoque cambiará drásticamente. Pero este escenario no está incluido en la pregunta.
(Vale la pena mencionar que incluso usando htmlspecialchars
la salida de una entrada de cadena puede diferir si las codificaciones de los caracteres son diferentes en cada paso).
Le sugiero que eche un vistazo a la función xss_clean
de CodeIgniter . Sé que no quieres limpiar, desinfectar ni filtrar nada. Solo quiere "detectar un mal comportamiento" y rechazarlo. Es exactamente por eso que te recomiendo que mires este código de función.
OMI, podemos encontrar allí un profundo conocimiento de vulnerabilidad XSS , que incluye todo el conocimiento que desea y necesita con su pregunta.
Entonces, mi respuesta corta / directa sería:
if (xss_clean($data) === $data)
Ahora, no necesita usar todo el framework CodeIgniter solo porque necesita esta única función, por supuesto. Pero creo que es posible que desee obtener toda la clase CI_Security
(en /system/core/Security.php
) y hacer algunas modificaciones para eliminar otras dependencias.
Como verá, el código xss_clean
es bastante complejo, ya que las vulnerabilidades XSS realmente lo son, y yo solo confiaría en él y no trataré de "reinventar esta rueda" ... EN mi humilde opinión, no puede deshacerse de las vulnerabilidades XSS simplemente detectando una docena de personajes.
No creo que deba implementar un gran algoritmo para verificar si la cadena tiene datos inseguros, los filtros y las expresiones regulares hacen el trabajo. Pero, si necesita una verificación más compleja, tal vez se ajuste a sus necesidades:
<?php
$strings = array();
$strings[] = <<<EOD
'';alert(String.fromCharCode(88,83,83))///';alert(String.fromCharCode(88,83,83))//";alert(String.fromCharCode(88,83,83))///";alert(String.fromCharCode(88,83,83))//--></SCRIPT>">''><SCRIPT>alert(String.fromCharCode(88,83,83))</SCRIPT>
EOD;
$strings[] = <<<EOD
'''';!--"<XSS>=&{()}
EOD;
$strings[] = <<<EOD
<SCRIPT SRC=http://ha.ckers.org/xss.js></SCRIPT>
EOD;
$strings[] = <<<EOD
This is a safe text
EOD;
$strings[] = <<<EOD
<IMG SRC="javascript:alert(''XSS'');">
EOD;
$strings[] = <<<EOD
<IMG SRC=javascript:alert(''XSS'')>
EOD;
$strings[] = <<<EOD
<IMG SRC=javascript:alert('XSS')>
EOD;
$strings[] = <<<EOD
perl -e ''print "<IMG SRC=java/0script:alert(/"XSS/")>";'' > out
EOD;
$strings[] = <<<EOD
<SCRIPT/XSS SRC="http://ha.ckers.org/xss.js"></SCRIPT>
EOD;
$strings[] = <<<EOD
</TITLE><SCRIPT>alert("XSS");</SCRIPT>
EOD;
libxml_use_internal_errors(true);
$sourceXML = ''<root><element>value</element></root>'';
$sourceXMLDocument = simplexml_load_string($sourceXML);
$sourceCount = $sourceXMLDocument->children()->count();
foreach( $strings as $string ){
$unsafe = false;
$XML = ''<root><element>''.$string.''</element></root>'';
$XMLDocument = simplexml_load_string($XML);
if( $XMLDocument===false ){
$unsafe = true;
}else{
$count = $XMLDocument->children()->count();
if( $count!=$sourceCount ){
$unsafe = true;
}
}
echo ($unsafe?''Unsafe'':''Safe'').'': <pre>''.htmlspecialchars($string,ENT_QUOTES,''utf-8'').''</pre><br />''."/n";
}
?>
Puede hacer uso de la función strip_tags en PHP . Esta función eliminará las etiquetas HTML y PHP de los datos proporcionados.
Por ejemplo, $ data es la variable que contiene su contenido, entonces puede usar esto de esta manera:
if (strlen($data) != strlen(strip_tags($data))){
return false;
}
else{
return true;
}
Verificará el contenido eliminado contra el contenido original. Si ambos son iguales , podemos esperar que no haya ninguna etiqueta HTML, y devuelve verdadero . De lo contrario, devuelve falso, ya que encontró algunas etiquetas HTML.
Puede usar una expresión regular si conoce los conjuntos de caracteres que están permitidos. SI un personaje está en el nombre de usuario que no está permitido, arroja un error:
[a-zA-Z0-9_.-]
Pon a prueba tus expresiones regulares aquí: http://www.perlfect.com/articles/regextutor.shtml
<?php
$username = "abcdef";
$pattern = ''/[a-zA-Z0-9_.-]/'';
preg_match($pattern, $username, $matches);
print_r($matches);
?>
Regex sigue siendo la forma más eficiente de resolver su problema. No importa qué frameworks planee usar, o se le recomiende usar, la forma más eficiente sería un código regex personalizado. Puede probar la cadena con una expresión regular y eliminar (o convertir) la sección afectada utilizando la función htmlcharacter.
No es necesario instalar ningún otro marco, o usar alguna aplicación prolija.
Si el motivo de la pregunta es para la prevención XSS , hay varias formas de explotar una vulnerabilidad XSS. Una gran hoja de trucos sobre esto es el XSS Cheatsheet en ha.ckers.org .
Pero la detección es inútil en este caso. Solo necesita prevención, y el uso correcto de htmlspecialchars / htmlentities en sus entradas de texto antes de guardarlas en su base de datos es más rápido y mejor que detectar malas entradas.
Si solo está "buscando protección para print ''<h3>'' . $name . ''</h3>''
", entonces sí, al menos el segundo enfoque es adecuado, ya que comprueba si el valor se interpretaría como marcado si no fue escapado (En este caso, el área donde $name
aparecería es contenido del elemento, y solo los caracteres &
, <
y >
tienen un significado especial cuando aparecen en el contenido del elemento.) (Para href
y atributos similares, la comprobación para "javascript: "puede ser necesario, pero como dijiste en un comentario, ese no es un objetivo").
Para fuentes oficiales, puedo referirme a la especificación XML :
Producción de contenido en la sección 3.1 : Aquí, el contenido consiste en elementos, secciones CDATA, instrucciones de procesamiento y comentarios (que deben comenzar con
<
), referencias (que deben comenzar con&
) y datos de caracteres (que contienen cualquier otro carácter legal). (Aunque un>
principal se trata como datos de caracteres en el contenido del elemento, muchas personas generalmente lo evitan junto con<
, y es mejor evitar que lamentar tratarlo como especial).Producción de valor de atributo en la sección 2.3 : un valor de atributo válido consiste en referencias (que deben comenzar con
&
) o datos de caracteres (que contienen cualquier otro carácter legal, pero no<
o el símbolo de comillas utilizado para ajustar el valor del atributo). Si necesita colocar entradas de cadena en atributos además del contenido del elemento, los caracteres"
y''
deben verificarse además de&
,<
y posiblemente>
(y otros caracteres son ilegales en XML).Sección 2.2 : Define qué puntos de código Unicode son legales en XML. En particular, null es ilegal en un documento XML y puede no mostrarse correctamente en HTML.
HTML5 (el borrador más reciente , que es un trabajo en progreso, describe un algoritmo de análisis muy elaborado para documentos HTML:
- El contenido del elemento corresponde al "estado de datos" en el algoritmo de análisis sintáctico. Aquí, la entrada de cadena no debe contener un carácter nulo,
<
(que comienza una nueva etiqueta), o&
(que comienza una referencia de carácter). - Los valores de atributo corresponden al "estado de valor de atributo anterior" en el algoritmo de análisis sintáctico. Para simplificar, suponemos que el valor del atributo está entre comillas dobles. En ese caso, el analizador se mueve al estado de "valor de atributo (comillas dobles)" . En este caso, la entrada de cadena no debe contener un carácter nulo,
"
(que termina el valor del atributo), o&
(que comienza una referencia de carácter).
Si las entradas de cadena se deben colocar en los valores de los atributos (a menos que colocarlos allí sea únicamente para fines de visualización), hay consideraciones adicionales a tener en cuenta. Por ejemplo, HTML 4 specifies :
Los agentes de usuario deben interpretar los valores de los atributos de la siguiente manera:
- Reemplazar entidades de caracteres con caracteres,
- Ignorar alimentaciones de línea,
- Reemplace cada retorno de carro o pestaña con un solo espacio.
Los agentes de usuario pueden ignorar el espacio en blanco inicial y posterior en los valores de los atributos CDATA [.]
La normalización del valor del atributo también se especifica en la especificación XML , pero aparentemente no en HTML5.
filter_input + FILTER_SANITIZE_STRING (hay muchas banderas de las que puedes elegir)
: - http://www.php.net/manual/en/filter.filters.sanitize.php
htmlpurifier.org hace un buen trabajo y es muy fácil de implementar. También podría usar un filtro de Zend Framework como Zend_Filter_StripTags.
HTML Purifier no solo arregla HTML .