getelementsbytagnamens attribute array php xml xpath code-injection

attribute - php dom get element by id



Limpieza/desinfección de los atributos de xpath (3)

Creé un documento XML de un solo elemento usando un DOM, uso el DOM para establecer el texto del elemento al valor proporcionado, y luego tomo el texto de la representación de cadena del DOM del XML. Esto garantizará que todo el personaje que se está escapando se haga correctamente, y no solo el personaje que escapa, que estoy pensando en ello de manera directa.

Editar: La razón por la que usaría el DOM en situaciones como esta es que las personas que escribieron DOM han leído la recomendación XML y yo no (al menos, no con el nivel de cuidado que tienen). Para elegir un ejemplo trivial, el DOM informará un error de análisis si el texto contiene un carácter que XML no permite (como # x8), porque los autores del DOM han implementado la sección 2.2 de la recomendación XML.

Ahora, podría decir: "bueno, obtendré la lista de caracteres inválidos de la recomendación XML y los eliminaré de la entrada". Por supuesto. Miremos la recomendación XML y ... um, ¿qué diablos son los bloques sustitutos Unicode? ¿Qué tipo de código tengo que escribir para deshacerme de ellos? ¿Pueden incluso entrar en mi texto en primer lugar?

Supongamos que lo descubro. ¿Hay otros aspectos de cómo la recomendación XML especifica representaciones de caracteres que no conozco? Probablemente. ¿Estos tendrán un impacto en lo que estoy tratando de implementar? Tal vez.

Si dejo que DOM haga la codificación de caracteres para mí, no tengo que preocuparme por nada de eso.

Necesito construir dinámicamente una consulta XPath para un atributo de elemento, donde el valor de atributo es proporcionado por el usuario. No estoy seguro de cómo limpiar o desinfectar este valor para evitar el equivalente XPath de un ataque de inyección SQL. Por ejemplo (en PHP):

<?php function xPathQuery($attr) { $xml = simplexml_load_file(''example.xml''); return $xml->xpath("//myElement[@content=''{$attr}'']"); } xPathQuery(''This should work fine''); # //myElement[@content=''This should work fine''] xPathQuery(''As should "this"''); # //myElement[@content=''As should "this"''] xPathQuery(''This/'ll cause problems''); # //myElement[@content=''This''ll cause problems''] xPathQuery(''/']/../privateElement[@content=/'private data''); # //myElement[@content='''']/../privateElement[@content=''private data'']

El último en particular es una reminiscencia de los ataques de inyección SQL de antaño.

Ahora, sé de hecho que habrá atributos que contienen comillas simples y atributos que contienen comillas dobles. Dado que estos se proporcionan como argumento para una función, ¿cuál sería la forma ideal de desinfectar la entrada para estos?


function xPathQuery($attr) { $xml = simplexml_load_file(''example.xml''); $to_encode = array(''&'', ''"''); $to_replace = array(''&amp;'',''&quot;''); $attr = replace($to_encode, $to_replace, $attr); return $xml->xpath("//myElement[@content=/"{$attr}/"]"); }

Ok, ¿qué hace?

Codifica todas las ocurrencias de & y "como & y; y & quot; en la cadena, lo que debería darle un selector seguro para ese uso particular. Tenga en cuenta que también reemplacé el interior ''en el xpath con". EDITAR: Desde entonces se ha señalado que ''se puede escapar como & apos ;, por lo que puede utilizar el método de comillas de cadena que prefiera.


XPath realmente incluye un método para hacerlo de manera segura, ya que permite referencias variables en la forma $varname en expresiones. La biblioteca en la que se basa SimpleXML de PHP proporciona una interfaz para suministrar variables , sin embargo, esto no está expuesto por la función xpath en su ejemplo.

Como una demostración de lo simple que puede ser esto:

>>> from lxml import etree >>> n = etree.fromstring(''<n a=/'He said "I&apos;m here"/'/>'') >>> n.xpath("@a=$maybeunsafe", maybeunsafe=''He said "I/'m here"'') True

Eso es usando lxml , un contenedor de Python para la misma biblioteca subyacente que SimpleXML, con una función xpath similar. Booleanos, números y conjuntos de nodos también se pueden pasar directamente.

Si cambiar a una interfaz XPath más capaz no es una opción, una solución cuando se le dé una cadena externa sería algo (siéntase libre de adaptarse a PHP) siguiendo las líneas de:

def safe_xpath_string(strvar): if "''" in strvar: return "'',/"''/",''".join(strvar.split("''")).join(("concat(''","'')")) return strvar.join("''''")

El valor de retorno se puede insertar directamente en su cadena de expresión. Como eso no es realmente muy legible, así es como se comporta:

>>> print safe_xpath_string("basic") ''basic'' >>> print safe_xpath_string(''He said "I/'m here"'') concat(''He said "I'',"''",''m here"'')

Tenga en cuenta que no puede usar el escape en el formulario &apos; fuera de un documento XML, ni tampoco son aplicables las rutinas genéricas de serialización XML. Sin embargo, la función XPath concat se puede usar para crear una cadena con ambos tipos de comillas en cualquier contexto.

Variante PHP

function safe_xpath_string($value) { $quote = "''"; if (FALSE === strpos($value, $quote)) return $quote.$value.$quote; else return sprintf("concat(''%s'')", implode("'', /"''/", ''", explode($quote, $value))); }