【问题标题】:Cleaning/sanitizing xpath attributes清理/清理 xpath 属性
【发布时间】:2008-10-09 19:32:27
【问题描述】:

我需要为元素属性动态构造一个 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 注入攻击。

现在,我知道事实上会有包含单引号的属性和包含双引号的属性。由于这些是作为函数的参数提供的,那么清理这些输入的理想方法是什么?

【问题讨论】:

    标签: php xml xpath code-injection


    【解决方案1】:

    XPath 实际上确实包含一种安全地执行此操作的方法,因为它允许 variable references 在表达式中以 $varname 的形式出现。 PHP 的 SimpleXML 所基于的库 provides an interface to supply variables,但在您的示例中是 is not exposed by the xpath function

    作为一个真正简单的演示:

    >>> 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,它是与 SimpleXML 相同的底层库的 python 包装器,具有类似的xpath function。布尔值、数字和节点集也可以直接传递。

    如果切换到功能更强大的 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"')
    

    注意,您不能在 XML 文档之外使用 &amp;apos; 形式的转义,通用 XML 序列化例程也不适用。但是,XPath 的 concat 函数可用于在任何上下文中创建具有两种引号类型的字符串。

    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)));
    }
    

    【讨论】:

      【解决方案2】:
      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}\"]");
      }
      

      好的,它有什么作用?

      它将字符串中所有出现的 & 和 " 编码为 & 和 ",这应该为您提供特定用途的安全选择器。请注意,我还将 xpath 中的内部 ' 替换为 "。编辑:后来有人指出 ' 可以转义为 ',因此您可以使用您喜欢的任何字符串引用方法。

      【讨论】:

      • 你可能忽略了'?
      • 是的,这就是我要找的那个。这里有一个所有 (5) 个 XML 实体的列表:en.wikipedia.org/wiki/…
      【解决方案3】:

      我将使用 DOM 创建一个单元素 XML 文档,使用 DOM 将元素的文本设置为提供的值,然后从 DOM 的 XML 字符串表示中获取文本。这将保证所有角色转义都正确完成,而不仅仅是我碰巧想到的角色转义。

      编辑:我在这种情况下使用 DOM 的原因是编写 DOM 的人已经阅读过 XML 推荐,而我没有(至少,没有他们所拥有的关心程度)。举一个简单的例子,如果文本包含 XML 不允许的字符(如 #x8),DOM 将报告解析错误,因为 DOM 的作者已经实现了 XML 推荐的第 2.2 节。

      现在,我可能会说,“好吧,我将只从 XML 推荐中获取无效字符列表,然后将它们从输入中删除。”当然。让我们看看 XML 推荐,然后……嗯,Unicode 代理块到底是什么?我必须编写什么样的代码才能摆脱它们?他们甚至可以首先进入我的文本吗?

      假设我想通了。 XML 建议如何指定我不知道的字符表示的其他方面?大概。这些会对我尝试实施的内容产生影响吗?也许吧。

      如果我让 DOM 为我进行字符编码,我就不必担心这些事情了。

      【讨论】:

      • 是的,它会的。例如,如果您使用 .Net DOM,XmlElement 的 InnerXml 属性将返回元素文本的标记。它的 Value 属性的行为与您描述的一样。
      • 但他说的是 PHP,我在(糟糕的)文档中看不到任何支持这一点的内容。
      • 它在里面。在 PHP 中,您将 DOMText 对象传递给 DOMDocument::saveXML 方法,该方法返回文本节点的标记 XML。
      猜你喜欢
      • 2011-03-13
      • 2012-10-28
      • 1970-01-01
      • 2011-05-04
      • 2016-10-02
      • 1970-01-01
      • 2015-12-26
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多