XPath注入缓解

时间:2013-10-21 15:08:55

标签: .net xpath code-injection

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

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

e.g。

"/Some/XPath/" + UntrustedNodeName

如果UntrustedNodeName"DoesNotExist | /Some/Other/XPath",则可能是攻击。

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

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

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

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

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

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

3 个答案:

答案 0 :(得分: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方法一起使用。

这提供了一种将用户提供的数据值合并到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(); }
        }
    }

}

答案 1 :(得分:0)

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

答案 2 :(得分:0)

我认为你可以做到以下几点。

  • 对于应表示节点名称的输入,请丢弃节点名称中无效的所有字符(比较"names" definition)。这可以通过正则表达式完成。
  • 对于应该表示字符串的输入,它很方便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()函数,如下所示:< / p>

      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()false())或数值(即10)插入,这些是然后在布尔上下文中使用时,通过XPath自动强制使用布尔值。
  • 如果您希望您的用户能够输入整个子表达式......那么。没有。