説明
java.beans.XMLDecoder はXMLを単なるデータとして解析するのではなく、オブジェクトの生成やメソッド呼び出しを復元します。信頼できない入力を解釈すると、攻撃者がアプリケーションの権限で意図しない操作を実行できるおそれがあります。問題になるのはデコーダーのコンストラクター呼び出しだけでなく、文書の解釈中に実行される処理です。
想定される影響
- コードの実行: 入力が選択したコンストラクターやメソッドにより、プロセスの権限で操作されるおそれがあります。
- 機密情報へのアクセス: アプリケーションが利用できるデータやシステムリソースが露出する可能性があります。
- データの変更とサービス障害: オブジェクトの状態を変更されたり、処理リソースを消費されたりするおそれがあります。
対処方法
- 信頼できないデータに
XMLDecoderを使用しないでください。必要なフィールドだけを持つ明示的なモデルとJSONなどのデータ形式に、プロトコルを変更してください。 - カスタム
ClassLoaderやクラスの許可リストだけで、XMLDecoderを安全にできると考えないでください。 - フィールド、型、サイズを検証し、任意のクラス名やポリモーフィックな型情報を受け入れないでください。XMLが必要な場合はオブジェクト復元ではなくデータパーサーを使い、DTDと外部エンティティも制限してください。
例
変更前
java
import java.beans.XMLDecoder;
import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;
public class InsecureXMLDecoder {
public static Object decode(String untrustedXml) {
try (XMLDecoder decoder = new XMLDecoder(new ByteArrayInputStream(
untrustedXml.getBytes(StandardCharsets.UTF_8)))) {
return decoder.readObject();
}
}
}
入力がオブジェクトや実行する操作を指定できます。オブジェクトを生成することと、実際にプロセスを起動することは別の操作です。
変更後
java
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
public class MessageReader {
private static final ObjectMapper MAPPER = new ObjectMapper();
public static String readMessage(String json) throws IOException {
if (json == null || json.length() > 4096) {
throw new IllegalArgumentException("Invalid message size");
}
JsonNode data = MAPPER.readTree(json);
if (data == null || !data.isObject() || data.size() != 1
|| !data.path("message").isTextual()) {
throw new IllegalArgumentException("Expected a message string");
}
return data.get("message").textValue();
}
}
JacksonのJSONツリーから、message という文字列だけを受け取ります。任意の型の復元は有効にしません。既存のXMLオブジェクト形式とは互換性がないため、呼び出し側もJSONを送るように変更してください。リクエスト本文のサイズ制限とアクセス権限の確認は、呼び出し境界で別途行ってください。