4

.NET 中是否有任何预先存在的方法来检测/防止 xpath 注入攻击?

我可以预见 2 个例子,但可能还有更多。

例如

"/Some/XPath/" + UntrustedNodeName

如果UntrustedNodeName是,"DoesNotExist | /Some/Other/XPath"那么这可能是一次攻击。

"/Some/XPath[" + UntrustedFilter + "]"

如果UntrustedFilter是,"1 = 1"那么这也可能是一次攻击。

我不假设我已经涵盖了这里的所有案例!

我猜这两种情况需要用不同的逻辑分别测试。

对于其他类型的攻击,有编码方法和参数化类来降低风险。对于 XPath,我找不到类似的东西。

(除了 - 我确实找到了这个:http ://www.tkachenko.com/blog/archives/000385.html但安装程序没有工作)

4

3 回答 3

3

正如 Michael Kay 所说,这里的正确方法是使用 XPath 变量,但是使用内置的 .NET API 有点棘手。我将在下面提供一个(非常简单的)类示例,该类允许您定义 XPath 变量。一旦你有了它,你可以像这样使用它:

VariableContext context = 
               new VariableContext { { "hello", 4 }, { "goodbye", "adios" } };

// node is a System.Xml.XmlNode object
XmlNodeList result = 
               node.SelectNodes("/my/field[. = $hello or . = $goodbye]", context);

同样的类也应该与XmlNode.SelectSingleNode()XPathNavigator.Select()XPathNavigator.SelectSingleNode()XPathNavigator.Evaluate()XElement.

这提供了一种将用户提供的数据值合并到 XPath 中的安全方法,但与 Tomalak 的回答一样,它没有解决如何允许用户提供整个 XPath 的问题。我认为没有一种方法可以确定 XPath 的一部分是否客观安全,因此如果您担心这会带来安全风险,那么唯一的解决方案就是不这样做。

这是课程。如果您想让它处理名称空间和类似的东西,则需要添加。

class VariableContext : XsltContext
{
    private Dictionary<string, object> m_values;

    public VariableContext()
    {
        m_values = new Dictionary<string, object>();
    }

    public void Add(string name, object value)
    {
        m_values[name] = value;
    }

    public override IXsltContextVariable ResolveVariable(string prefix, string name)
    {
        return new XPathVariable(m_values[name]);
    }

    public override int CompareDocument(string baseUri, string nextbaseUri)
    {
        throw new NotImplementedException();
    }

    public override bool PreserveWhitespace(XPathNavigator node)
    {
        throw new NotImplementedException();
    }

    public override IXsltContextFunction ResolveFunction(string prefix, string name, 
                                                         XPathResultType[] ArgTypes)
    {
        throw new NotImplementedException();
    }

    public override bool Whitespace
    {
        get { throw new NotImplementedException(); }
    }

    private class XPathVariable : IXsltContextVariable
    {
        private object m_value;

        internal XPathVariable(object value)
        {
            m_value = value;
        }

        public object Evaluate(XsltContext xsltContext)
        {
            return m_value;
        }

        public bool IsLocal
        {
            get { throw new NotImplementedException(); }
        }

        public bool IsParam
        {
            get { throw new NotImplementedException(); }
        }

        public XPathResultType VariableType
        {
            get { throw new NotImplementedException(); }
        }
    }

}
于 2013-10-31T10:29:08.943 回答
0

只需避免使用字符串连接构建 XPath 表达式。改用参数/变量。

于 2013-10-21T21:23:00.830 回答
0

我认为您可以执行以下操作。

  • 对于应该代表节点名称的输入,丢弃节点名称中的所有无效字符(比较“名称”定义)。这可以通过正则表达式完成。
  • 对于应该表示字符串的输入,XPath 中没有转义序列会派上用场。

    • 要么从用户输入中丢弃所有单引号,要么只使用表达式模板中的单引号字符串。您可以避免注入,因为除了单引号之外,没有办法从单引号字符串中逃脱。

      var xpathTmpl = "/this/is/the/expression[@value = '{0}']";
      
      var input = "asd'asd";
      var safeInput = input.Replace("'", "");
      
      var xpath = String.Format(xpathTmpl, safeInput);
      // -> "/this/is/the/expression[@value = 'asdasd']"
      
    • 或者反过来。同样的效果,更多的反斜杠(至少在 C# 中)。

      var xpathTmpl = "/this/is/the/expression[@value = \"{0}\"]";
      
      var input = "asd\"asd";
      var safeInput = input.Replace("\"", "");
      
      var xpath = String.Format(xpathTmpl, safeInput);
      // -> "/this/is/the/expression[@value = "asdasd"]"
      

      …当然这不是 100% 好,因为您更改了用户的输入。

    • 如果您想逐字表示用户输入,则必须在您选择的 XPath 字符串分隔符处将其拆分为多个部分(例如,单引号)并使用 XPath 的concat()函数,如下所示:

      var xpathTmpl = "/this/is/the/expression[@value = {0}]";
      
      var input = "asd'asd";
      var inputParts = input.Split('\'');
      var safeInput = "concat('" + String.Join("', \"'\", '", inputParts) + "')";
      
      var xpath = String.Format(xpathTmpl, safeInput);
      // -> "/this/is/the/expression[@value = concat('asd', "'", 'asd')]"
      

      将其包装在实用程序函数中,动态 XPath 构建变得易于管理。

  • 数字很​​容易通过健全性检查 ( float.Parse()) 和String.Format().
  • 布尔值相对容易,可以将它们作为 XPath 原生布尔值 ( true()or false()) 或数值值 (ie 1or 0) 插入,然后在布尔上下文中使用时由 XPath 自动强制转换为布尔值。
  • 如果您希望您的用户能够输入整个子表达式......好吧。不。
于 2013-10-22T09:20:07.120 回答