JPCERT コーディネーションセンター

IDS16-J. XML インジェクションを防ぐ

IDS16-J. XML インジェクションを防ぐ

Extensible Markup Language (XML) は、データの保存や構造化、転送に役立つよう設計されている。プラットフォームに依存せず、柔軟で、比較的単純なため、XML は幅広い用途で使われている。しかし、その汎用性ゆえに、XML は「XML インジェクション」をはじめとする幅広い攻撃に対して脆弱である。

XML ドキュメントに組み込まれる入力文字列データを提供できるユーザは、XML タグを挿入できる。これらのタグは XML パーサによって解釈され、データの上書きを引き起こす可能性がある。

購入可能な商品の数量をユーザが指定できるオンラインストアのアプリケーションでは、以下のような XML ドキュメントを生成する場合がある。

<item>
  <description>Widget</description>
  <price>500.0</price>
  <quantity>1</quantity>
</item>

攻撃者は購入数量の代わりに以下のような文字列を入力するかもしれない。

1</quantity><price>1.0</price><quantity>1

この場合、XML は以下のように解決される。

<item>
  <description>Widget</description>
  <price>500.0</price>
  <quantity>1</quantity><price>1.0</price><quantity>1</quantity>
</item>

XML パーサは、最初の価格フィールドを2番目の価格フィールドで上書きし、商品の価格を1ドルに変更するよう、この例の XML を解釈する可能性がある。他にも、攻撃者は、コメントブロックや CDATA 区切りなどの特殊な文字列を挿入し、XML の意味を破損させるかもしれない。

違反コード

以下の違反コード例では、サーバに送る XML クエリをクライアントメソッドが単純な文字列連結で組み立てている。このメソッドは入力値を検査しないため、XML インジェクションが可能である。

import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

public class OnlineStore {
  private static void createXMLStreamBad(final BufferedOutputStream outStream,
      final String quantity) throws IOException {
    String xmlString = "<item>\n<description>Widget</description>\n"
        + "<price>500</price>\n" + "<quantity>" + quantity
        + "</quantity></item>";
    outStream.write(xmlString.getBytes());
    outStream.flush();
  }
} 
適合コード (入力値検査)

個別のデータや、送信先となるコマンドインタプリタまたはパーサに応じて、信頼できないユーザ入力の無害化に適切な方法をとる必要がある。以下の解決法では、quantity が符号無し整数であるか検査している。

import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

public class OnlineStore {
  private static void createXMLStream(final BufferedOutputStream outStream,
      final String quantity) throws IOException, NumberFormatException {
    // quantity が符号無し整数 (count) である場合のみ XML 文字列に書き込む。
    int count = Integer.parseUnsignedInt(quantity);
    String xmlString = "<item>\n<description>Widget</description>\n"
        + "<price>500</price>\n" + "<quantity>" + count + "</quantity></item>";
    outStream.write(xmlString.getBytes());
    outStream.flush();
  }
} 
適合コード (XML Schema)

XML インジェクションの試みを検知するためのより一般的な方法は、文書型定義 (DTD) やスキーマを使って検査することだ。インジェクションが有効な XML と間違われないよう、スキーマは厳密に定義する必要がある。前述の XML の検査に適したスキーマを以下に示す。

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="item">
  <xs:complexType>
    <xs:sequence>
      <xs:element name="description" type="xs:string"/>
      <xs:element name="price" type="xs:decimal"/>
      <xs:element name="quantity" type="xs:nonNegativeInteger"/>
    </xs:sequence>
  </xs:complexType>
</xs:element>
</xs:schema>

スキーマは schema.xsd ファイルとして利用できるものとする。以下の適合コードでは、このスキーマを使って XML インジェクションの成功を阻止している。また、XML外部エンティティ (XXE) 攻撃を防ぐため、「IDS17-J. XML 外部エンティティ(実体)攻撃を防ぐ」で定義される CustomResolver クラスにも依存している。

import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.StringReader;

import javax.xml.XMLConstants;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;

import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

public class OnlineStore {

  private static void createXMLStream(final BufferedOutputStream outStream,
      final String quantity) throws IOException {
    String xmlString;
    xmlString = "<item>\n<description>Widget</description>\n"
        + "<price>500.0</price>\n" + "<quantity>" + quantity
        + "</quantity></item>";
    InputSource xmlStream = new InputSource(new StringReader(xmlString));
    // 前述のスキーマを使い、検査用 SAX パーサを作る。
    SchemaFactory sf = SchemaFactory
        .newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
    DefaultHandler defHandler = new DefaultHandler() {
      public void warning(SAXParseException s) throws SAXParseException {
        throw s;
      }
      public void error(SAXParseException s) throws SAXParseException {
        throw s;
      }
      public void fatalError(SAXParseException s) throws SAXParseException {
        throw s;
      }
    };
    StreamSource ss = new StreamSource(new File("schema.xsd"));
    try {
      Schema schema = sf.newSchema(ss);
      SAXParserFactory spf = SAXParserFactory.newInstance();
      spf.setSchema(schema);
      SAXParser saxParser = spf.newSAXParser();
      // 独自の Entity Resolver を設定するため、XML Reader を作る必要がある。
      XMLReader reader = saxParser.getXMLReader();
      reader.setEntityResolver(new CustomResolver());
      saxParser.parse(xmlStream, defHandler);
    } catch (ParserConfigurationException x) {
      throw new IOException("Unable to validate XML", x);
    } catch (SAXException x) {
      throw new IOException("Invalid quantity", x);
    }
    // Our XML is valid, proceed
    outStream.write(xmlString.getBytes());
    outStream.flush();
  }
}

XML の検査にスキーマや DTD を使うのは、無害化されていない入力を含む可能性のある XML を受け取る場合に便利である。このような XML 文字列がまだ構築されていない場合、XML を構築する前に入力値を無害化する方が性能面で優れている。

リスク評価

処理や保存の前にユーザ入力を無害化しないと、インジェクション攻撃を引き起こす可能性がある。

ルール

深刻度

可能性

修正コスト

優先度

レベル

IDS16-J

P12

L1

自動検出
ツール バージョン チェッカー 説明
The Checker Framework

2.1.3

Tainting Checker Trust and security errors (see Chapter 8)
Fortify 1.0

Missing_XML_Validation

Implemented
Klocwork

2024.4

JAVA.SV.XML.INVALID Implemented
Parasoft Jtest
2024.1
CERT.IDS16.TDXML Protect against XML data injection
関連する脆弱性

CVE-2008-2370 には、Apache Tomcat バージョン4.1.0から4.1.37、5.5.0から5.5.26、6.0.0から6.0.16に影響を与えた脆弱性について記述されている。この脆弱性は、RequestDispatcher が使用されている場合、Tomcat が URI からクエリ文字列を除去する前にパスの正規化を行うというもので、遠隔の攻撃者はリクエスト引数に .. (ドット2つ) を含めることでディレクトリトラバーサル攻撃を行い、任意のファイルを読み取ることができた。

関連ガイドライン

CERT C コーディングスタンダード

STR02-C. 複雑なサブシステムに渡すデータは無害化する

SEI CERT C++ Coding Standard

VOID STR02-CPP. Sanitize data passed to complex subsystems

SEI CERT Perl Coding Standard IDS33-PL. Sanitize untrusted data passed across a trust boundary

ISO/IEC TR 24772:2013

Injection [RST]

MITRE CWE

CWE-116, Improper Encoding or Escaping of Output

参考文献

[OWASP 2005]

A Guide to Building Secure Web Applications and Web Services

[OWASP 2007]

OWASP Top 10 for Java EE

[OWASP 2008]

Testing for XML Injection (OWASP-DV-008)

[Seacord 2015]

[W3C 2008]

Section 4.4.3, "Included If Validating"

翻訳元

これは以下のページを翻訳したものです。

IDS16-J. Prevent XML Injection (revision 24)

Top へ

Topへ
最新情報(RSSメーリングリストTwitter