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つ) を含めることでディレクトリトラバーサル攻撃を行い、任意のファイルを読み取ることができた。
関連ガイドライン
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] |
CWE-116, Improper Encoding or Escaping of Output |
参考文献
[OWASP 2005] |
A Guide to Building Secure Web Applications and Web Services |
[OWASP 2007] |
|
[OWASP 2008] |
|
[Seacord 2015] |
|
[W3C 2008] |
Section 4.4.3, "Included If Validating" |
翻訳元
これは以下のページを翻訳したものです。
IDS16-J. Prevent XML Injection (revision 24)