12 Java API for XML Processing (JAXP)セキュリティ・ガイド

JDKおよびJava XML APIは、アプリケーションがXML関連の攻撃によって悪用されないようにするのに役立つ様々な手段とツールで何年にもわたり改善されてきました。このガイドでは、Java API for XML Processing (JAXP)のセキュア処理機能を使用してアプリケーションおよびシステムを保護する方法を示します。

詳細は、java.xmlモジュールのサマリーを参照してください。

XML処理におけるセキュリティの問題

XML処理は、アプリケーションを一定の脆弱性に晒すことがあります。最も顕著で有名な攻撃は、XML外部エンティティ(XXE)インジェクション攻撃と指数関数的エンティティ展開攻撃で、XML爆弾やBillion laughs攻撃とも呼ばれます。これらの攻撃は、そのサービスを拒否することでシステムの重大な破損を引き起こしたり、さらに悪いことに機密データの喪失につながったりすることがあります。

アプリケーションの要件およびオペレーティング環境を評価して、潜在的な脅威のレベル(たとえば、信頼できないXMLソースにアプリケーションが公開されているかどうか、またはどの程度公開されているか)を評価する必要があります。

XML外部エンティティ・インジェクション攻撃

XML、XMLスキーマおよびXSLT標準では、外部リソースを参照するシステム識別子を通じてXMLドキュメントに外部コンテンツを埋め込むことができる構造をいくつか定義します。一般に、XMLプロセッサは、これらの外部リソースのほぼすべてを解決および取得します。外部リソースの挿入をサポートするコンストラクトのリストは、「XML、スキーマおよびXSLT標準でサポートされる外部リソース」を参照してください。また、一部のコンストラクトでは、外部関数を通じてアプリケーションを実行できます。XML外部エンティティ(XXE)インジェクション攻撃は、解決、取得または実行できる外部リソースの制限によって保護されていないXMLプロセッサを悪用します。これにより、パスワードなどの機密データが開示されたり、コードを任意に実行できるようになったりすることがあります。

XML、スキーマおよびXSLT標準でサポートされている外部リソース

XML、スキーマおよびXSLT標準では、外部リソースを必要とする次のコンストラクトがサポートされています。JDK XMLプロセッサのデフォルトの動作では、接続を作成し、指定された外部リソースをフェッチします。

  • 外部DTD: 外部ドキュメント・タイプ定義(DTD)を参照します。たとえば:

    <!DOCTYPE root_element SYSTEM "url">
  • 外部エンティティ参照: 外部データを参照します。次に構文を示します。

    <!ENTITY name SYSTEM "url">
  • 一般エンティティ参照。たとえば:

    <?xml version="1.0" standalone="no" ?>
    <!DOCTYPE doc [<!ENTITY otherFile SYSTEM "otherFile.xml">]>
    <doc>
        <a>
            <b>&otherFile;</b>
        </a>
    </doc>
  • 外部パラメータ・エンティティ: 次に構文を示します。

    <!ENTITY % name SYSTEM uri>

    次に、例を示します。

    <?xml version="1.0" standalone="no"?>
        <!DOCTYPE doc [
          <!ENTITY % ent1 SYSTEM "http://www.example.com/student.dtd">
          %ent1;
        ]>
  • XInclude: XMLドキュメントに外部情報セットを含めます。たとえば:
    <Book xmlns:xi="http://www.w3.org/2001/XInclude">
        <xi:include href=toc.xml"/>
        <xi:include href=part1.xml"/>
        <xi:include href=part2.xml"/>
        <xi:include href=index.xml"/>
    </Book>
  • schemaLocation属性とimport要素およびinclude要素を使用してXMLスキーマ・コンポーネントを参照します。たとえば:

    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
        <xs:include schemaLocation="http://www.example.com/schema/schema1.xsd"/>
        <!-- ... -->
    </xs:schema>
  • importまたはinclude要素を使用したスタイル・シートの結合。次に構文を示します。
    <xsl:include href="include.xsl"/>
  • xml-stylesheet処理命令: スタイルシートをXMLドキュメントに含めるために使用します。たとえば:
    <?xml-stylesheet href="include.xsl" type="text/xsl"?>
  • XSLT document()関数: 外部XMLドキュメントのノードにアクセスするために使用します。たとえば:
    <xsl:variable name="dummy" select="document('DocumentFunc2.xml')"/>

指数関数的エンティティ展開攻撃

XML爆弾またはBillion laughs攻撃とも呼ばれる指数関数的エンティティ展開攻撃は、XMLパーサーを含むサービス拒否攻撃です。基本的な悪用は、各レイヤーが次のレイヤーのいくつかのエンティティを参照する、ネストされたエンティティの複数のレイヤーの使用です。次に、深くネストされたエンティティ参照を含むSOAPドキュメントのサンプルを示します。

<?xml version="1.0" encoding ="UTF-8"?>
<!DOCTYPE bbb[
    <!ENTITY x100 "bbb">
    <!ENTITY  x99 "&x100;&x100;">
    <!ENTITY  x98 "&x99;&x99;">
    ...
    <!ENTITY   x2 "&x3;&x3;">
    <!ENTITY   x1 "&x2;&x2;">
]>
<SOAP-ENV:Envelope xmlns:SOAP-ENV=...>
    <SOAP-ENV:Body>
        <ns1:aaa xmlns:ns1="urn:aaa" SOAP-ENV:encodingStyle="...">
            <foobar xsi:type="xsd:string">&x1;</foobar>
        </ns1:aaa>
    </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

XMLパーサーは、このようなドキュメントを検出すると、参照を展開してエンティティ宣言を解決しようとします。参照はネストされているため、展開は、それぞれが参照するエンティティ数によって指数関数的になります。このようなプロセスによって、XMLパーサーが100%のCPU時間と大量のメモリーを消費し、最終的にシステムのメモリーが不足する可能性があります。

セキュアなXML処理のためのJAXPの構成

JAXPは、XMLドキュメントの解析、直列化、変換、問合せおよびトラバースを行うためのAPIのセットで構成されます。JAXP APIを参照してください。

JAXPは、ファクトリおよびプロセッサを通じてセキュリティのレイヤーを追加します。ファクトリを通じてJAXPからAPIにアクセスします。これにより、セキュリティ要件に基づいて設定したJAXPプロパティに従ってAPIが構成されます。ファクトリは、それぞれのプロセッサを使用して構成し、インスタンス化します。ファクトリおよびプロセッサを参照してください。

JAXPプロセッサは、JAXPプロパティを使用して構成します。JAXPプロパティは、JAXPファクトリを通じて、システム・プロパティとして、またはJAXP構成ファイルで設定できます。JAXPプロパティを使用した構成を参照してください。

セキュリティ関連のプロパティでは、セキュアなXML処理のためにJAXPを構成する際に設定できるプロパティについて説明します。

また、JAXPを使用すると、カスタム・リゾルバおよびカタログを登録することで、外部リソースへの参照を捕捉し、ローカル・リソースで解決できます。これにより、外部リソースの読取りとアクセスの必要がなくなるため、潜在的なリスクのソースを除去するのに役立ちます。リゾルバおよびカタログの使用を参照してください。

JAXP API

JAXPは、XML処理に不可欠なXMLの技術および標準を構築したAPIのセットで構成されます。これには、次のAPIが含まれています:

  • 解析:
  • 直列化: StAXおよびExtensible Stylesheet Language Transformation (XSLT) (javax.xml.transformパッケージ)
  • 変換: XSLT
  • XMLドキュメントの問合せおよびトラバース: XML XPath言語(XPath) (javax.xml.xpathパッケージ)
  • 外部リソースの解決: XMLカタログAPI (javax.xml.catalogパッケージ)

ファクトリおよびプロセッサ

ファクトリは、各JAXP APIのエントリ・ポイントです。これらは、アプリケーションがプロセッサを作成する前にJAXPプロパティをプログラムで設定できるようにするメソッドを提供します。ファクトリはJAXP検索メカニズムもサポートしており、JDK実装ではなくサードパーティ実装を使用してアプリケーションをデプロイできます。

プロセッサは、それぞれの領域で処理を制御および実行するパーサー(またはリーダー)、シリアライザ(またはライター)、バリデータおよびトランスフォーマを集約したものです。ファクトリは、対応するファクトリを構成し、インスタンス化します。たとえば、DocumentBuilderFactoryおよびSAXParserFactoryファクトリを使用して、それぞれDocumentBuilderおよびSAXParserプロセッサを構成し、インスタンス化します。

JAXPプロパティを使用した構成

JAXPプロセッサは、JAXPプロパティを使用して構成します。次に、JAXPプロパティを設定する方法を、優先順位の高いものから低いものの順に示します。たとえば、ファクトリを通じてJAXPプロパティの値を設定すると、別の方法で設定された他の値がオーバーライドされます。

すべてのJAXPプロパティが、これらすべての方法によって設定できるわけではありません。特定のJAXPプロパティを設定できるメソッドを確認するには、java.xmlモジュールのサマリーを参照してください。

次のいずれかの方法で特定のJAXPプロパティを設定していない場合、JavaランタイムはデフォルトのJAXPプロパティ・ファイルで指定された値を使用します。このファイルにプロパティが存在しない場合、Javaランタイムはそのデフォルト値を使用します。ただし、セキュア処理機能(FSP)がオンの場合、Javaランタイムで使用する値はより限定的になります(該当する場合)。詳細は、java.xmlモジュールのサマリーにある実装固有のプロパティの表を参照してください。

その他のJAXPプロパティの詳細は、デフォルトのJAXP構成ファイル<java-home>/conf/jaxp.propertiesを参照してください。

JAXPファクトリを使用したJAXPプロパティの設定

アプリケーションのコードを変更したり、新しいアプリケーションを作成する場合は、JAXPファクトリまたはパーサーを通じてJAXPプロパティを設定できます。これらのプロパティは、次のインタフェースを使用して設定します。

    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    dbf.setAttribute(name, value);
 
    SAXParserFactory spf = SAXParserFactory.newInstance();
    SAXParser parser = spf.newSAXParser();
    parser.setProperty(name, value);

    SchemaFactory schemaFactory = SchemaFactory.newInstance(schemaLanguage);
    schemaFactory.setProperty(name, value);
 
    TransformerFactory factory = TransformerFactory.newInstance();
    factory.setAttribute(name, value);
 
    XMLInputFactory xif = XMLInputFactory.newInstance();
    xif.setProperty(name, value);

    XPathFactory xf = XPathFactory.newInstance();
    xf.setProperty(name, value);

次に、処理制限の設定例を示します。

    dbf.setAttribute("jdk.xml.entityExpansionLimit", "2000");
    dbf.setAttribute("jdk.xml.totalEntitySizeLimit", "100000");
    dbf.setAttribute("jdk.xml.maxParameterEntitySizeLimit", "10000"); 
    dbf.setAttribute("jdk.xml.maxElementDepth", "100");

    factory.setAttribute("jdk.xml.xpathTotalOpLimit", "1000"); 
    xf.setProperty("jdk.xml.xpathExprGrpLimit", "20");  

次に、DOMパーサーを外部DTDのローカル接続のみに制限する例を示します。

    dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "file, jar:file");

アプリケーション内のパーサー・モジュールが信頼できないソースを処理する場合、さらにアクセスを制限できます。次のコードは、JAXP構成ファイルおよびシステム・プロパティによって指定されたコードをオーバーライドし、XMLプロセッサがローカル・ファイルのみを読み取れるようにします:

    DocumentBuilderFactory dbf =
    DocumentBuilderFactory.newInstance();   
    dbf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "file");
    // ...   
    SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);   
    schemaFactory.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "file");   
    schemaFactory.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "file");

セキュアなXML処理のためのJAXPの構成で説明されているように、JAXPファクトリを通じて指定されたJAXPプロパティは、スコープが最も狭く、ファクトリによって作成されたプロセッサにのみ影響するため、デフォルト設定、システム・プロパティおよびJAXP構成ファイル内の設定がオーバーライドされます。JAXPファクトリを使用してJAXPプロパティを設定すると、使用しているJDKリリースや、JAXPプロパティを他の手段で設定するかどうかに関係なく、アプリケーションの動作が同じようになります。

システム・プロパティとしてのJAXPプロパティの設定

システム・プロパティは、アプリケーションのコードを変更できない場合に便利です。

JDKの起動全体に対してJAXPプロパティを設定するには、コマンド行で対応するシステム・プロパティを設定します。たとえば、アプリケーションMyAppで外部DTDおよびスキーマへのアクセスが必要な場合は、システム・プロパティjavax.xml.accessExternalDTDおよびjavax.xml.accessExternalSchemaを次のように設定します:

java -Djavax.xml.accessExternalDTD="file,http" -Djavax.xml.accessExternalSchema="file, http" MyApp

JAXPプロパティをアプリケーションの一部のみに設定するには、対応するシステム・プロパティをその部分の前に設定し、後でクリアします。たとえば、アプリケーションで外部DTDおよびスキーマへのアクセスが必要な場合、これらの行をアプリケーションの初期化コード・ブロックに追加します。

    System.setProperty("javax.xml.accessExternalDTD", "file, http");
    System.setProperty("javax.xml.accessExternalSchema", "file, http");

その後、アプリケーションでXMLドキュメントの処理を実行した後、またはアプリケーションを終了する前に、次のようにプロパティをクリアします。

    System.clearProperty("javax.xml.accessExternalDTD");   
    System.clearProperty("javax.xml.accessExternalSchema");

ノート:

処理制限に関連するJAXPプロパティはJDK実装に固有ですが、外部アクセス制限に関連するプロパティは標準プロパティです。
JAXP構成ファイルでのJAXPプロパティの設定

JAXPプロパティは、JAXP構成ファイル(java.util.Propertiesファイル)で設定できます。(Javaプロパティの詳細は、Javaチュートリアルプロパティの説明を参照してください。)

JAXP構成ファイルの形式

JAXP構成ファイルは、JAXPプロパティの名前と値(各行に1つの名前と値のペア)を含むテキスト・ファイルです。たとえば、次の次のJAXP構成ファイルでは、maxGeneralEntitySizeLimit処理制限プロパティを2000に設定し、stylesheet処理命令、document関数、およびimport要素とinclude要素によって設定される外部参照のファイルおよびHTTPプロトコルへのアクセスを制限します。

jdk.xml.maxGeneralEntitySizeLimit=2000
javax.xml.accessExternalStylesheet=file, http

XMLプロセッサによる外部接続を許可しない場合は、すべてのアクセス外部制限をfileのみに設定できます。

javax.xml.accessExternalDTD=file
javax.xml.accessExternalSchema=file
javax.xml.accessExternalStylesheet=file

アプリケーションがXMLプロセッサを通じて外部ファイルを誤って読み取ることを防ぐには、次のJAXP構成ファイルのように外部アクセス制限を設定します:

javax.xml.accessExternalDTD=""   
javax.xml.accessExternalSchema=""   
javax.xml.accessExternalStylesheet=""

ヒント:

JAXPプロパティをシステム・プロパティとして指定できる場合は、JAXP構成ファイルで同じJAXPプロパティを指定できます。特定のJAXPプロパティの値を設定する場所を確認するには、java.xmlモジュールのサマリーを参照してください。

ユーザー定義のJAXP構成ファイルの指定

独自のJAXP構成ファイルを使用するには、java.xml.config.fileシステム・プロパティで名前と場所を指定します。絶対パスでないファイル・パスを指定すると、現在の作業ディレクトリに対する相対パスになります。JAXPファクトリのインスタンス化時にこのシステム・プロパティの値が指定されていない場合、その値のチェックはこれ以上試行されません。

ユーザー定義のJAXP構成ファイルは、JAXP実装が初期化されるときに1回のみ読み取られます。これは、JAXPファクトリがインスタンス化された後に変更しても機能しないことを意味します。

デフォルトのJAXP構成ファイル

JDKには、デフォルトのJAXP構成ファイル<java_home>/conf/jaxp.propertiesが含まれています。ただし、かわりに独自のユーザー定義のJAXP構成ファイルを作成することをお薦めします。

システム・プロパティjava.xml.config.fileでユーザー定義のJAXP構成ファイルを指定し、そのファイルが存在する場合は、その設定によってデフォルトのJAXP構成ファイルの設定がオーバーライドされます。

セキュリティ関連のプロパティ

次の項では、セキュアなXML処理のためにJAXPを構成する際に設定できるプロパティについて説明します:

処理制限用のJAXPプロパティ

XML処理は、メモリー集中型の操作である場合があります。信頼できないソースからのXML、XSDおよびXSLを受け入れるアプリケーションでは特に、処理制限用のJAXPプロパティを使用して、過剰なメモリー消費を回避するステップをとる必要があります。

アプリケーションの要件およびオペレーティング環境を評価して、システム構成の許容可能な処理制限を判断し、それに応じてこれらの制限を設定します。たとえば、サイズ関連の制限を使用して、不適切なXMLソースによる大量のメモリー消費を防止します。アプリケーションでメモリー消費を許容レベルに制御できるようにするには、jdk.xml.entityExpansionLimitプロパティを使用します。

JDK XMLパーサーは、デフォルトで処理制限を監視します。DOMおよびSAXパーサーでは、セキュア処理機能(FSP)がデフォルトでオンになっているため、制限がオンになります。また、StAXパーサーは、FSPをサポートしていなくても、デフォルトで処理制限を遵守します。

次の表に、JDKでサポートされる処理制限用のJAXPプロパティを示します。これらの各処理制限の値は正の整数です。0以下の値は、制限がないことを示します。値が整数でない場合は、NumericFormatExceptionがスローされます。これらのプロパティの値は、ファクトリを通じて、システム・プロパティとして、またはJAXP構成ファイルで指定できます。

詳細は、java.xmlモジュールのサマリーにある実装固有のプロパティの表を参照してください。

表12-1 JAXP処理制限のプロパティ

プロパティ名 説明 デフォルト値 サポートされているファクトリ
jdk.xml.elementAttributeLimit 1つの要素で使用できる属性の数を制限します。 10000

DocumentBuilderFactory
SAXParserFactory
XMLInputFactory
SchemaFactory
TransformerFactory

jdk.xml.entityExpansionLimit エンティティの展開数を制限します。 64000

DocumentBuilderFactory
SAXParserFactory
XMLInputFactory
SchemaFactory
TransformerFactory

jdk.xml.entityReplacementLimit すべてのエンティティ参照のノードの合計数を制限します。 3000000

DocumentBuilderFactory
SAXParserFactory
XMLInputFactory
SchemaFactory
TransformerFactory

jdk.xml.maxElementDepth 要素の最大の深さを制限します。 0

DocumentBuilderFactory
SAXParserFactory
XMLInputFactory
SchemaFactory
TransformerFactory

jdk.xml.maxGeneralEntitySizeLimit すべての一般エンティティの最大サイズを制限します。 0

DocumentBuilderFactory
SAXParserFactory
XMLInputFactory
SchemaFactory
TransformerFactory

jdk.xml.maxOccurLimit "unbounded"以外の値を持つmaxOccurs属性を含むW3C XMLスキーマの文法の構築時に作成できるコンテンツ・モデル・ノードの数を制限します。 5000

DocumentBuilderFactory
SAXParserFactory
XMLInputFactory
SchemaFactory
TransformerFactory

jdk.xml.maxParameterEntitySizeLimit 複数のパラメータ・エンティティのネストの結果を含む、パラメータ・エンティティの最大サイズを制限します。 1000000

DocumentBuilderFactory
SAXParserFactory
XMLInputFactory
SchemaFactory
TransformerFactory

jdk.xml.maxXMLNameLimit 要素名、属性名、名前空間の接頭辞やURIなど、XML名の最大サイズを制限します。 1000

DocumentBuilderFactory
SAXParserFactory
XMLInputFactory
SchemaFactory
TransformerFactory

jdk.xml.totalEntitySizeLimit 一般エンティティとパラメータ・エンティティを含むすべてのエンティティの合計サイズを制限します。サイズはすべてのエンティティの集約として計算されます。 5x10^7

DocumentBuilderFactory
SAXParserFactory
XMLInputFactory
SchemaFactory
TransformerFactory

jdk.xml.xpathExprGrpLimit XPath式に含めることができるグループの数を制限します。 10

TransformerFactory
XPathFactory

jdk.xml.xpathExprOpLimit XPath式に含めることができる演算子の数を制限します。 100

TransformerFactory
XPathFactory

jdk.xml.xpathTotalOpLimit XSLスタイルシートのXPath演算子の総数を制限します。 100000 TransformerFactory
処理制限をいつ使用するか

適用する処理制限および使用する値を決定する場合は、システム・レベルで、アプリケーションで使用可能なメモリー量、および信頼できないソースからのXML、XSDまたはXSLソースが受け入れられて処理されるかどうかを検討します。アプリケーション・レベルでは、DTDなどの特定のコンストラクトを使用するかどうかを検討します。

メモリー設定および制限

XML処理では、メモリーが大量に消費される可能性があります。消費できるメモリー量は、特定の環境におけるアプリケーションの要件によって異なります。不適切なXMLデータの処理によってメモリーが過剰に消費されるのを防ぐ必要があります。

通常、デフォルトの制限は、メモリー使用量がPCなどの小規模なハードウェア・システムに対して許容される量であるほとんどのアプリケーションで正当なXML入力が可能になるように設定されます。不正な入力が大量のメモリーを消費する前にそれを捕捉できるように、制限を可能な最小値に設定することをお薦めします。

制限は相関していますが、完全に冗長ではありません。すべての制限に適切な値を設定する必要があります。通常、制限はデフォルトより大幅に小さい値に設定する必要があります。

たとえば、ENTITY_EXPANSION_LIMITおよびGENERAL_ENTITY_SIZE_LIMITを設定して、過剰なエンティティ参照を防ぐことができます。ただし、展開とエンティティ・サイズの正確な組合せが不明な場合は、TOTAL_ENTITY_SIZE_LIMITが全体的な制御として機能できます。同様に、TOTAL_ENTITY_SIZE_LIMITは置換テキストの合計サイズを制御しますが、テキストがXMLの非常に大きいチャンクである場合、ENTITY_REPLACEMENT_LIMITはテキストに出現できるノードの総数に対する制限を設定し、システムの過負荷を防ぎます。

getEntityCountInfoプロパティを使用した制限の見積り

制限に設定する必要がある値を分析するために、http://www.oracle.com/xml/jaxp/properties/getEntityCountInfoという特殊なプロパティを使用できます。Javaチュートリアル処理制限サンプルに関する項の次のコード・スニペットは、プロパティの使用例を示しています。

    public static final String ORACLE_JAXP_PROPERTY_PREFIX =
        "http://www.oracle.com/xml/jaxp/properties/";
    // ...
    public static final String JDK_ENTITY_COUNT_INFO = 
        ORACLE_JAXP_PROPERTY_PREFIX + "getEntityCountInfo";
    // ...
    parser.setProperty(JDK_ENTITY_COUNT_INFO, "yes");

W3C MathML 3.0のDTDで処理制限サンプルを実行すると、次の表が出力されます。

表12-2 W3C MathML 3.0のDTDを使用したJAXP処理制限サンプルの実行

プロパティ 制限 サイズ合計 サイズ エンティティ名
ENTITY_EXPANSION_LIMIT 64000 1417 0 null
MAX_OCCUR_NODE_LIMIT 5000 0 0 null
ELEMENT_ATTRIBUTE_LIMIT 10000 0 0 null
TOTAL_ENTITY_SIZE_LIMIT 50000000 55425 0 null
GENERAL_ENTITY_SIZE_LIMIT 0 0 0 null
PARAMETER_ENTITY_SIZE_LIMIT 1000000 0 7303 %MultiScriptExpression
MAX_ELEMENT_DEPTH_LIMIT 0 2 0 null
MAX_NAME_LIMIT 1000 13 13 null
ENTITY_REPLACEMENT_LIMIT 3000000 0 0 null

この例では、エンティティ参照の合計数(エンティティ展開)は1417で、デフォルトの上限は64000です。すべてのエンティティの合計サイズは55425で、デフォルトの上限は50000000です。最大のパラメータ・エンティティは、すべての参照が解決された後に7303の長さを持つ%MultiScriptExpressionです。デフォルトの上限は1000000です。

これがアプリケーションで処理されることが想定される最大ファイルである場合、制限は小さい数値に設定することをお薦めします。たとえば、ENTITY_EXPANSION_LIMITの場合は2000、TOTAL_ENTITY_SIZE_LIMITの場合は100000、PARAMETER_ENTITY_SIZE_LIMITの場合は10000です。

外部アクセス制限用のJAXPプロパティ

外部アクセス制限用のJAXPプロパティを対応するシステム・プロパティとともに使用すると、外部接続を規制できます。

外部アクセス制限を使用すると、許可できるまたは許可できない外部接続のタイプを指定できます。プロパティ値は、プロトコルのリストです。JAXPプロセッサは、プロトコルをリスト内のプロトコルと照合することによって、特定の外部接続が許可されているかどうかをチェックします。プロセッサは、リスト上にある場合は接続を確立しようとし、そうでない場合は拒否しようとします。これらのJAXPプロパティをカスタム・リゾルバおよびカタログAPIとともに使用して(「リゾルバおよびカタログの使用」を参照)、ローカル・リソースを拒否および解決することにより、外部接続のリスクを軽減します。

ノート:

factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true)などのAPIを通じてセキュア処理機能(FSP)を明示的にオンにし、すべての外部接続を無効にします。

外部アクセス制限JAXPプロパティは、javax.xml.XMLConstantsで次のように定義されます。

これらのプロパティの値は、システム・プロパティとして、またはJAXP構成ファイルで指定できます。

表12-3 外部アクセス制限のJAXPプロパティ

プロパティ 説明 デフォルト値
javax.xml.accessExternalDTD 外部DTDおよび外部エンティティ参照へのアクセスを指定されたプロトコルに制限します all。すべてのプロトコルへの接続が許可されます
javax.xml.accessExternalSchema schemaLocation属性、import要素およびinclude要素によって設定された外部参照へのアクセスを指定されたプロトコルに制限します all。すべてのプロトコルへの接続が許可されます
javax.xml.accessExternalStylesheet stylesheet処理命令、document関数、importおよびinclude要素によって設定された外部参照へのアクセスを指定されたプロトコルに制限します。 all。すべてのプロトコルへの接続が許可されます

外部アクセス制限のJAXPプロパティの値

外部アクセス制限用のすべてのJAXPプロパティが同じ形式の値を持ちます。

  • : カンマで区切られたプロトコルのリスト。プロトコルは、URIのスキーム部分であり、JARプロトコルの場合はjarに、コロンで区切られたスキーム部分が付け加えられたものになります。スキームは次のように定義されます。

    scheme = alpha *( alpha | digit | "+" | "-" | "." )

    ここで、alpha=a-zおよびA-Zです。

    JARプロトコルは、jar[:scheme]として定義されます

    プロトコルでは大文字と小文字が区別されません。値に含まれる、Character.isSpaceCharで定義された空白はすべて無視されます。プロトコルの例として、filehttpおよびjar:fileがあります。

  • デフォルト値: デフォルト値は実装固有です。JDKの場合、デフォルト値はallで、すべてのプロトコルに対するアクセス権を付与します。

  • すべてのアクセスの許可: キーワードallは、すべてのプロトコルに対するアクセス権を付与します。たとえば、JAXP構成ファイルでjavax.xml.accessExternalDTD=allを指定すると、システムは以前のように外部DTDおよびエンティティ参照へのアクセスに対する制限なしで機能できます。

  • アクセスの拒否: 空の文字列("")は、どのプロトコルに対してもアクセス権が付与されていないことを意味します。たとえば、JAXP構成ファイルにjavax.xml.accessExternalDTD=""を指定すると、JAXPプロセッサは外部接続を拒否します。

外部アクセス制限をいつ使用するか

XMLプロセッサは、デフォルトで、XMLソースで参照される外部リソースへの接続および読取りを試行します。これにより、アプリケーションおよびシステムは、外部接続によって発生するリスクに晒される可能性があることに注意してください。そのため、アプリケーションでは外部アクセス制限プロパティを使用した外部接続の制限を検討することをお薦めします。

信頼できるXMLドキュメントのみを処理する内部アプリケーションおよびシステムでは、これらの制限が不要な場合があります。外部接続を規制するためにJavaセキュリティ・マネージャに依存するアプリケーションおよびシステムでも、それらが不要な場合があります。ただし、外部アクセス制限はXMLプロセッサに固有であり、プロセスの最上位レイヤーにあることに注意してください。つまり、プロセッサは接続を行う前にこれらの制限をチェックします。したがって、外部接続リスクに対する、より直接的な追加の保護として機能します。

警告:

セキュリティ・マネージャおよびそれに関連するAPIは非推奨であり、今後のリリースでは削除されます。セキュリティ・マネージャの代わりとなるものはありません。詳細および代替手段については、JEP 411を参照してください。

外部アクセス制限のプロパティをカスタムのリゾルバおよびカタログ(「リゾルバおよびカタログの使用」を参照)とともに使用すると、外部接続を効果的に管理し、リスクを軽減できます。

信頼できるソースを含む信頼できる環境であっても、外部アクセス制限とリゾルバの両方を使用して外部ソースへの依存を最小限にすることをお薦めします。

JAXPプロパティの優先順位および外部アクセスの制限

外部アクセス制限は、次のような状況で制限しようとする関連コンストラクトには影響しません。

  • リゾルバがあり、リゾルバによって返されたソースがnullではない場合: これは、SAXおよびDOMパーサーで設定できるエンティティ・リゾルバ、StAXパーサー上のXMLリゾルバ、SchemaFactory上のLSResourceResolverValidatorまたはValidatorHandler、あるいはトランスフォーマ上のURIResolverに適用されます。

  • SchemaFactoryからnewSchemaメソッドを呼び出してスキーマが明示的に作成された場合。

  • 外部リソースが不要な場合: たとえば、JDKでは次の機能とプロパティがサポートされており、外部DTDをロードしないようにプロセッサに指示したり外部エンティティを解決するために使用できます。

    http://apache.org/xml/features/disallow-doctype-decl true
    http://apache.org/xml/features/nonvalidating/load-external-dtd false
    http://xml.org/sax/features/external-general-entities false
    http://xml.org/sax/features/external-parameter-entities false
拡張関数のJAXPプロパティ

TransformerおよびXPathに対してはセキュア処理機能(FSP)がデフォルトでオフになるため、拡張機能を使用できます。信頼できないソースからのドキュメントを処理するアプリケーションでは、拡張関数機能をオフにすることをお薦めします。これを行うには、次の2つの方法があります。

  • FSPをtrueに設定します。たとえば:

        TransformerFactory tf = TransformerFactory.newInstance();          
        tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
  • TransformerFactoryまたはXPathFactoryを通じて、システム・プロパティとして、またはJAXP構成ファイルで、jdk.xml.enableExtensionFunctionsプロパティをfalseに設定します。

Javaセキュリティ・マネージャをインストールした結果として拡張関数が無効になっている場合、アプリケーションでは、jdk.xml.enableExtensionFunctionsプロパティをtrueに設定して拡張関数機能を再度有効にすることもできます。次の表で、このプロパティを定義します。

表12-4 jdk.xml.enableExtensionFunctionsプロパティ

プロパティ 説明 デフォルト値 サポートされているファクトリ
jdk.xml.enableExtensionFunctions trueの場合、XSLTおよびXPath拡張関数を使用できます。falseの場合、拡張関数は使用できません。 false

TransformerFactory
XPathFactory

警告:

セキュリティ・マネージャおよびそれに関連するAPIは非推奨であり、今後のリリースでは削除されます。セキュリティ・マネージャの代わりとなるものはありません。詳細および代替手段については、JEP 411を参照してください。
サードパーティ・パーサーのJAXPプロパティ

JDKでは、クラスパスにサードパーティ製のパーサーが存在する場合でも、常にシステムデフォルト・パーサーが使用されます。JDKのシステムデフォルト・パーサーをオーバーライドするには、TransformerFactorySchemaFactoryまたはXPathFactoryを通じて、システム・プロパティとして、またはJAXP構成ファイルで、jdk.xml.overrideDefaultParserプロパティをtrueに設定します。

表12-5 jdk.xml.enableExtensionFunctionsプロパティ

プロパティ 説明 デフォルト値 サポートされているファクトリ
jdk.xml.overrideDefaultParser trueの場合、サードパーティのパーサー実装を使用して、JDKのトランスフォーマバリデータおよびXPath実装のシステムデフォルト・パーサーをオーバーライドできます。falseの場合、サードパーティ製パーサー実装の使用が無効になります。 false

TransformerFactory
SchemaFactory
XPathFactory

DTDプロパティ

アプリケーションでDTDが必要ない場合は、DTD処理を無効化して、サービス拒否、XML外部エンティティ(XXE)、サーバー側リクエストの偽造(SSRF)など、多くの一般的なDTD関連の攻撃に対抗することを検討してください。

SAXおよびDOMパーサーに対するDTD処理の無効化

SAXおよびDOMパーサーのDTD処理を無効にするには、ファクトリを通じてhttp://apache.org/xml/features/disallow-doctype-decl機能をtrueに設定します。次のコード・スニペットはSAXパーサーのDTDを無効化します。受け取ったXMLドキュメントにDOCTYPE宣言が含まれていると、致命的なエラーがスローされます。

    final static String DISALLOW_DTD =
        "http://apache.org/xml/features/disallow-doctype-decl";
    // ...
    SAXParserFactory spf = SAXParserFactory.newInstance();      
    spf.setFeature(DISALLOW_DTD, true);

StAXパーサーに対するDTD処理の無効化

StAXパーサーのDTD処理を無効にするには、XMLInputFactory.setPropertyメソッドを使用してプロパティSupportDTDfalseに設定します:

    XMLInputFactory xif = XMLInputFactory.newInstance();
    xif.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);

リゾルバおよびカタログの使用

JDK XMLプロセッサでカスタム・リゾルバおよびカタログを登録して、外部リソースへの参照を捕捉し、ローカル・リソースで解決できます。この機能によって、外部リソースの読み取りとアクセスの必要がなくなるため、潜在的なリスクのソースを除去するのに役立ちます。

Java XMLリゾルバ

Java XML APIでは、JDK XMLプロセッサに登録して外部リソースを解決できる様々なリゾルバがサポートされます。これらのリゾルバには、SAXおよびDOMパーサー用のエンティティ・リゾルバ、StAXパーサー用のXMLリゾルバ、検証用のLSResourceResolverおよび変換用のURIResolverが含まれます。

SAXおよびDOMのエンティティ・リゾルバ

SAXは、DOMでもサポートされるインタフェースorg.xml.sax.EntityResolverを定義します。これにより、アプリケーションでエンティティ解決プロセスをトレース実行し、独自のタームでエンティティ解決を実行できます。インタフェースの定義は次のとおりです。

package org.xml.sax;

public interface EntityResolver {
    public InputSource resolveEntity(String publicID, String systemID)
        throws SAXException;
}

その後、SAXドライバでインタフェースの実装を登録できます。

    EntityResolver resolver = ...;
    SAXParserFactory factory = SAXParserFactory.newInstance();
    factory.setNamespaceAware(true);
    XMLReader reader = factory.newSAXParser().getXMLReader();
    reader.setEntityResolver(resolver);

または、DOMビルダーで登録できます。

    DocumentBuilder builder =
        DocumentBuilderFactory.newInstance().newDocumentBuilder();       
    docBuilder.setEntityResolver(resolver);
StAX用のXMLResolver

StAXでは、javax.xml.stream.XMLResolverインタフェースを定義します。

package javax.xml.stream;

public interface XMLResolver {
    public Object resolveEntity(
        String publicID, String systemID,
        String baseURI, String namespace)
        throws XMLStreamException;
}

これをStAXファクトリに登録できます。

    XMLResolver resolver = ...;
    XMLInputFactory xif = XMLInputFactory.newInstance();
    xif.setProperty(XMLInputFactory.RESOLVER, resolver);
javax.xml.transform用のURIResolver

javax.xml.transform APIでは、URIResolverインタフェースを介した外部リソースのカスタム解決がサポートされます。

package javax.xml.transform;

public interface URIResolver {
    public Source resolve(String href, String base)
        throws TransformerException;
}

URIResolverの実装は、次のようにトランスフォーマに登録できます。

    URIResolver resolver = ...;
    TransformerFactory tf = TransformerFactory.newInstance();
    Transformer t =
      tf.newTransformer(new StreamSource(
        new StringReader("xsl source")));
    t.setURIResolver(resolver);
javax.xml.validation用のLSResourceResolver

javax.xml.validation APIでは、LSResourceResolverインタフェースを通じてDocument Object Model Level 3 Load and Save (DOM LS) DOMがサポートされます。

package org.w3c.dom.ls;

public interface LSResourceResolver {
    public LSInput resolveResource(
        String type, String namespaceURI, String publicId,
        String systemId, String baseURI);
}

LSResourceResolverの実装は、次のようにSchemaFactoryに登録できます。

    SchemaFactory schemaFactory =
        SchemaFactory.newInstance("http://www.w3.org/2001/XMLSchema");
    LSResourceResolver resolver = ...;
    schemaFactory.setResourceResolver(resolver);
カタログAPI

XML Catalog APIでは、Organization for the Advancement of Structured Information Standards (OASIS) XMLカタログ、OASIS標準V1.1がサポートされます。このAPIは、JDK XMLプロセッサによって完全に実装されており、使用が簡単です。『Java Platform, Standard Editionコア・ライブラリ』「XMLカタログAPI」を参照してください。

XMLカタログAPIを使用して、外部リソースをCatalogResolverインタフェースで解決し、JDK XMLプロセッサ上でカタログを有効化します。

カタログ・リゾルバ

カタログ・オブジェクトとして構成されたローカル・リソースで外部参照を置き換えるカスタム・リゾルバとしてCatalogResolverを使用できます。「Java XMLリゾルバ」で説明されているように、EntityResolverXMLResolverURIResolverまたはLSResourceResolverのかわりにCatalogResolverをファクトリまたはプロセッサに登録できます。次のコード・スニペットでは、CatalogResolverSAXParserFactoryEntityResolverとして登録されます。

    URI catalogUri = URI.create("file:///users/auser/catalog/catalog.xml")
    CatalogResolver cr =
        CatalogManager.catalogResolver(CatalogFeatures.defaults(), catalogUri);
    SAXParserFactory factory = SAXParserFactory.newInstance();
    factory.setNamespaceAware(true);
    XMLReader reader = factory.newSAXParser().getXMLReader();
    reader.setEntityResolver(cr);
JDK XMLプロセッサでのカタログの有効化

JDK XMLプロセッサは、カタログAPIをネイティブ機能として実装します。したがって、プロセッサの外部でCatalogResolverをインスタンス化する必要はありません。必要なのは、setPropertyメソッド、setAttributeメソッドまたはシステム・プロパティを使用して、またはJAXP構成ファイル内で、XMLプロセッサにカタログ・ファイルを登録することだけです。XMLプロセッサによって自動的にカタログを使用したマッピングが実行されます。次のコード・スニペットは、XMLInputFactoryを使用してStAXパーサーにカタログを登録する方法を示しています。

    String catalog = "file:///users/auser/catalog/catalog.xml";
    XMLInputFactory factory = XMLInputFactory.newInstance();
    factory.setProperty(CatalogFeatures.Feature.FILES.getPropertyName(), catalog);

詳細は、『Java Platform, Standard Editionコア・ライブラリ』「XMLカタログAPI」を参照してください。

JAXPプロパティからのエラーの処理

JAXPプロパティを設定する際に、アプリケーションでorg.xml.sax.SAXNotRecognizedExceptionを捕捉することをお薦めします。これにより、それらをサポートしない古いリリースでアプリケーションが正しく動作します。

たとえば、Javaチュートリアル処理制限のサンプルからのisNewPropertySupportedメソッドでは、JDK_GENERAL_ENTITY_SIZE_LIMITプロパティをサポートするバージョンのJDKでサンプルが実行されるかどうかが検出されます。

    public boolean isNewPropertySupported() {
        try {
            SAXParser parser = getSAXParser(false, false, false);
            parser.setProperty(JDK_GENERAL_ENTITY_SIZE_LIMIT, "10000");
        } catch (ParserConfigurationException ex) {
            fail(ex.getMessage());
        } catch (SAXException ex) {
            String err = ex.getMessage();
            if (err.indexOf("Property '" + JDK_GENERAL_ENTITY_SIZE_LIMIT +
                                           "' is not recognized.") > -1) {
                // expected before this patch
                debugPrint("New limit properties not supported. Samples not run.");
                return false;
            }
        }
        return true;
    }

入力ファイルに、over-the-limit例外を引き起こすコンストラクトが含まれている場合、アプリケーションはエラー・コードをチェックして失敗の性質を判断できます。処理制限について、次のエラー・コードが定義されています。

  • EntityExpansionLimit: JAXP00010001
  • ElementAttributeLimit: JAXP00010002
  • MaxEntitySizeLimit: JAXP00010003
  • TotalEntitySizeLimit: JAXP00010004
  • MaxXMLNameLimit: JAXP00010005
  • maxElementDepth: JAXP00010006
  • EntityReplacementLimit: JAXP00010007

エラー・コードの形式は、次のとおりです。

"JAXP" + components (two digits) + error category (two digits) + sequence number

したがって、コードJAXP00010001は、JAXPベース・パーサーのセキュリティ制限EntityExpansionLimitを表します。

外部アクセス制限によって設定された制限が原因で外部リソースへのアクセスが拒否された場合、次の形式でエラーとともに例外がスローされます。

[type of construct]: Failed to read [type of construct]
    "[name of the external resource]", because "[type of restriction]"
    access is not allowed due to restriction set by the
    [property name] property.

たとえば、次のように仮定します。

  • ACCESS_EXTERNAL_DTD JAXPプロパティは次のように設定されます。

    parser.setProperty(
        "http://javax.xml.XMLConstants/property/accessExternalDTD", "file");
  • アプリケーションは、外部DTDをHTTPプロトコルでフェッチしようとします。

  • パーサーはhttp://www.example.com/dtd/properties.dtdへの外部参照を含むXMLファイルを解析しました。

エラー・メッセージは次のようになります。

External DTD: Failed to read external DTD
    "http://www.example.com/dtd/properties.dtd", because "http"
    access is not allowed due to restriction set by the
    accessExternalDTD property.

JAXPセキュリティに関する一般的な推奨事項

アプリケーションおよびシステムのセキュリティを確保するためのJAXPのプロパティと機能の構成に関する一般的な推奨事項を次に示します。

  • 環境に応じたプロパティ設定でユーザー定義のJAXP構成ファイルを作成して指定します。JAXP構成ファイルでのJAXPプロパティの設定を参照してください。その後、工場出荷時の設定またはシステム・プロパティを使用して、アプリケーションの特定の要件に従って個々の機能およびプロパティを調整します。
  • 処理制限では、アプリケーションが必要とする最大量に対応できるだけの大きさになるように調整します。
  • 外部アクセス制限の場合は、リゾルバの使用を含め、アプリケーションの外部リソースへの依存を軽減または排除してから、これらの制限を強化します。
  • ローカル・カタログを設定し、すべてのXMLプロセッサでカタログAPIを有効にして、アプリケーションの外部リソースへの依存をさらに軽減します。

セキュリティ・マネージャとの関係

警告:

セキュリティ・マネージャおよびそれに関連するAPIは非推奨であり、今後のリリースでは削除されます。セキュリティ・マネージャの代わりとなるものはありません。詳細および代替手段については、JEP 411を参照してください。

SecurityManagerの有無に関係なく、JAXPプロパティは接続が試行される前に最初にチェックされます。つまり、SecurityManagerによってアクセス権を付与されている場合でも、接続をブロックできます。たとえば、JAXPプロパティがHTTPプロトコルを許可しないように設定されている場合、アプリケーションにSocketPermissionがあっても、実際には接続試行がブロックされます。

接続を制限する目的で、SecurityManagerは下位レベルと見なすことができます。JAXPプロパティが評価された後、アクセス権がチェックされます。たとえば、アプリケーションにSocketPermissionがない場合は、JAXPプロパティがHTTP接続を許可するように設定されていても、SecurityExceptionがスローされます。

SecurityManagerが存在する場合、セキュア処理機能(FSP)はtrueに設定されます。この動作によって外部アクセス制限がオンになることはありません。

付録A: Java API for XML Processingの用語および定義の用語集

表12-6 JAXP用語集

用語 定義
JAXP Java API for XML Processing
Java SE XML API JAXP JSRに定義され、Java SEに統合されているAPI
Java XML API Java SE XML APIと同等の用語
Java XMLの機能およびプロパティ Java SEの仕様で定義されているXML関連の機能とプロパティ
java.xml java.xmlモジュール
JDK XML Java XML APIのJDK実装
JDK XMLパーサー XMLパーサーのJDK実装
JDK XMLプロパティ JDK実装専用プロパティ
FSP FEATURE_SECURE_PROCESSING

付録B: JavaおよびJDK XMLの機能とプロパティの命名規則

JavaおよびJDK XMLの機能とプロパティは、javax.xml.XMLConstantsクラスに定義されています。この機能には、接頭辞http://javax.xml.XMLConstants/feature、プロパティhttp://javax.xml.XMLConstants/propertyがあります。対応するシステム・プロパティがある場合、その接頭辞はjavax.xmlです。

JDK XMLプロパティは、JDK実装専用のプロパティです。プロパティの接頭辞は、JDK 8以前の場合はhttp://www.oracle.com、JDK 9以降の場合はjdk.xmlです。次の表に、この命名規則をまとめます。

表12-7 JavaおよびJDK XMLの機能とプロパティの命名規則

スコープ APIプロパティ接頭辞 システム・プロパティ接頭辞 Java SEおよびJDKバージョン
Java SE

http://javax.xml.XMLConstants/feature

http://javax.xml.XMLConstants/property

javax.xml 1.4以降
JDK http://www.oracle.com/xml/jaxp/properties jdk.xml 7以降
JDK jdk.xml jdk.xml 9以降