Очистка/очистка атрибутов xpath

Мне нужно динамически построить запрос XPath для атрибута элемента, где значение атрибута предоставляется пользователем. Я не уверен, как очистить или очистить это значение, чтобы предотвратить XPath-эквивалент атаки SQL-инъекций. Например (в 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']

Последнее, в частности, напоминает атаки SQL-инъекций прошлого.

Теперь я точно знаю, что будут атрибуты, содержащие одинарные кавычки, и атрибуты, содержащие двойные кавычки. Поскольку они предоставляются в качестве аргумента функции, каков был бы идеальный способ очистки ввода для них?


person Community    schedule 09.10.2008    source источник


Ответы (3)


На самом деле XPath включает способ сделать это безопасно, поскольку он разрешает ссылки на переменные. в виде $varname в выражениях. Библиотека, на которой основан PHP SimpleXML, предоставляет интерфейс для предоставления переменных, однако это не отображается функцией xpath в вашем примере.

В качестве демонстрации того, насколько простым это может быть:

>>> 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

Это использует lxml, оболочку python для той же базовой библиотеки, что и SimpleXML, с аналогичным функция xpath. Логические значения, числа и наборы узлов также могут передаваться напрямую.

Если переход на более функциональный интерфейс XPath невозможен, обходной путь при заданной внешней строке будет чем-то (не стесняйтесь адаптироваться к PHP) в соответствии с строками:

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

Возвращаемое значение может быть непосредственно вставлено в строку выражения. Поскольку это на самом деле не очень читабельно, вот как это работает:

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

Обратите внимание, что вы не можете использовать экранирование в форме &apos; вне XML-документа, а также неприменимы общие процедуры сериализации XML. Однако функцию concat XPath можно использовать для создания строки с обоими типами кавычек в любом контексте.

Вариант 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)));
}
person gz.    schedule 11.10.2008

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}\"]");
}

Хорошо, что он делает?

Он кодирует все вхождения & и " as и в строке, что должно дать вам безопасный селектор для этого конкретного использования. Обратите внимание, что я также заменил внутренний ' в xpath на ". РЕДАКТИРОВАТЬ: с тех пор было указано, что ' можно экранировать как , поэтому вы можете использовать любой метод цитирования строки, который вы предпочитаете.

person Chris Marasti-Georg    schedule 09.10.2008
comment
Вы, наверное, не замечаете? - person Robert Rossney; 10.10.2008
comment
Да, это тот, кого я ищу. Здесь есть список всех (5) объектов XML: en.wikipedia.org/wiki/ - person Chris Marasti-Georg; 10.10.2008

Я бы создал XML-документ с одним элементом, используя DOM, использовал DOM, чтобы установить текст элемента в предоставленное значение, а затем взял текст из строкового представления XML в DOM. Это гарантирует, что все побеги персонажей будут выполнены правильно, а не только побеги персонажей, о которых я случайно подумал.

Изменить: причина, по которой я бы использовал DOM в подобных ситуациях, заключается в том, что люди, которые написали DOM, прочитали рекомендацию по XML, а я нет (по крайней мере, не с тем уровнем осторожности, который у них есть). Чтобы выбрать тривиальный пример, DOM сообщит об ошибке синтаксического анализа, если текст содержит символ, который не разрешен XML (например, #x8), потому что авторы DOM реализовали раздел 2.2 рекомендации XML.

Теперь я мог бы сказать: «Ну, я просто возьму список недопустимых символов из рекомендации XML и удалю их из ввода». Конечно. Давайте просто посмотрим рекомендацию по XML и… гм, что это за суррогатные блоки Unicode? Какой код мне нужно написать, чтобы избавиться от них? Могут ли они вообще попасть в мой текст?

Предположим, я разобрался с этим. Существуют ли другие аспекты того, как рекомендации XML определяют представления символов, о которых я не знаю? Наверное. Повлияют ли они на то, что я пытаюсь реализовать? Может быть.

Если я позволю DOM сделать за меня кодировку символов, мне не придется беспокоиться ни о чем из этого.

person Robert Rossney    schedule 09.10.2008
comment
Да, это будет. Например, если вы используете .Net DOM, свойство InnerXml XmlElement возвращает разметку текста элемента. Его свойство Value ведет себя так, как вы описываете. - person Robert Rossney; 10.10.2008
comment
Но он говорит о PHP, и я не вижу ничего в (плохой) документации, подтверждающей это. - person Chris Marasti-Georg; 10.10.2008
comment
Это там. В PHP вы передаете объект DOMText методу DOMDocument::saveXML, который возвращает размеченный XML текстового узла. - person Robert Rossney; 10.10.2008