如何从代码层防御10大安全威胁中的Xpath Injection?

本文转自OneAPM技术社区,系OneAPM架构师吕龙涛原创文章

普遍性和可检测性:
Xpath 注入是OWASP TOP10 安全威胁中 A1 Injection 中的一种,注入漏洞发生在应用程序将不可信的数据发送到解释器时。虽然注入漏洞很容易通过审查代码发现,但是却不容易在测试中发现。

影响严重:
注入能导致数据丢失或数据破坏、缺乏可审计性或者是拒绝服务。注入漏洞有时候甚至能导致完全主机接管。

从代码层次如何防御:
首先我们先来看一下在 Java 中引用 xpath 需要用的 lib 库:

  • javax.xml.xpath
  • org.jdom.xpath
  • org.jdom2.xpath等

那么xpath注入是从哪些途径进入到代码逻辑的呢?大家仔细思考一下无外乎三个途径:cookie、header、request parameters/input。如果我们能对这三个注入源头进行严格得入参检查是否就能够防御绝大部分的注入攻击了呢?

答案是可以防御大部分注入攻击,下面我们就一起来看一下如何进行有效得进行入参检查: 我们将入参都转化为 Map 对象,Map<K, Collection<V>> asMap();

然后通过CheckMap(finnal Map<String, String> params)方法,检查入参是否合法。
下面我们来实现这个CheckMap内部方法:
1. 通过遍历检查Map中key得合法性

Java代码
  1. for (final String key : params.keySet()) {
  2.        if (this.checkString(key)) {
  3.            return true;
  4.        }

2.检查每一个key对应得value得合法性:

Java代码
  1. final Collection<String> coll = (Collection<String>)params.get((Object)key);
  2.        for (final String input : coll) {
  3.            if (this.checkString(input)) {
  4.                return true;
  5.            }
  6.        }

做完这些就是细节方面得检测了,具体得就是 checkString 如何实现。笔者暂时能想到认为一个入参是 xpath 得检测条件大概有以下几点:

Java代码
  1. private boolean checkString(final String input) {
  2.     return null != input && input.length() > 1 && (this.parser.IsOutBoundary(input) || (-1 != input.indexOf(39) && (this.parser.IsOutBoundary(input.replace("'", "''")) || this.parser.IsOutBoundary(input.replace("'", "\\'")))) || (-1 != input.indexOf(34) && (this.parser.IsOutBoundary(input.replace("\"", "\"\"")) || this.parser.IsOutBoundary(input.replace("\"", "\\\"")))) || this.parser.IsQuoteUnbalanced(input));
  3. }

通过查 ASCII 码表我们知道39对应“'”,34对应“"”;所以有了检测条件

Java代码
  1. -1!=input.indexOf(39)&&(this.parser.IsOutBoundary(input.replace("'","''")
  2. -1!=input.indexOf(34)&& this.parser.IsOutBoundary(input.replace("\"", "\"\""))

上述检测条件中用到两个关键方法IsOutBoundary和IsQuoteUnbalance

Java代码
  1. public boolean IsOutBoundary(String input) {
  2.     int offset = 0;
  3.     if (null == input || input.length() <= 1) {
  4.         return false;
  5.     }
  6.     input = input.toLowerCase();
  7.     while (true) {
  8.         final int x = this.getRawValue().indexOf(input, offset);
  9.         final int y = x + input.length();
  10.         if (-1 == x) {
  11.             return false;
  12.         }
  13.         final int ceil = this.getCeiling(this.boundaries, x + 1);
  14.         if (-1 != ceil && ceil < y) {
  15.             return true;
  16.         }
  17.         offset = y;
  18.     }
  19. }
  20. public boolean IsQuoteUnbalanced(String input) {
  21.     input = input.toLowerCase();
  22.     return this.getRawValue().contains(input) && this.stack.size() > 0 && input.indexOf(this.stack.peek()) != -1;
  23. }
  24.  public String getRawValue() {
  25.         return this.input;
  26.     }
  27.  private int getCeiling(final List<Integer> boundaries, final int value) {
  28.     for (final int x : boundaries) {
  29.         if (x >= value) {
  30.             return x;
  31.         }
  32.     }
  33.     return -1;
  34. }

漏洞攻击示例
看完代码是如何检查得我们来一个真真正正 Xpath 注入的示例;来检验一下我们代码是都有效。

WebGoat 是 OWASP 推出得一款开源的含有大量漏洞攻击的应用,在 Github 上可以直接搜到源码。

*我们找到 Xpath Injection 得 lession *,如下图:

hints提示我们攻击的入参:

引用
Try username: Smith' or 1=1 or 'a'='a and a password: anything

点击 Submit 之后神奇得事情出现了!

面对这样得一种攻击那么我们该如何防御呢?如果对代码感兴趣得同学可以把 WebGoat 得源码 down 下来;然后将上面得入参检测得方法封装一下嵌入到 WebGoat 得源码中,然后我们再攻击一下,那么接下来会发生什么样的事情呢?

Xpath 查询失败了,并没有返回任何结果,攻击被拦截之后,前端页面没有渲染任何东西。由此可见入参检查在注入类得漏洞防御中可以起到立竿见影得作用。

Xpath 查询失败了,并没有返回任何结果,攻击被拦截之后,前端页面没有渲染任何东西。由此可见入参检查在注入类得漏洞防御中可以起到立竿见影得作用。

参考文献:

  1. da shang
    donate-alipay
               donate-weixin weixinpay

发表评论↓↓