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

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

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時間と大量のメモリーを消費し、最終的にシステムのメモリーが不足する可能性があります。

セキュア処理機能(FSP)

javax.xml.XMLConstants.FEATURE_SECURE_PROCESSINGとして定義されているセキュア処理機能(FSP)は、XML処理を保護するための中心的なメカニズムです。XMLをセキュアに試行して処理するようXMLプロセッサ(パーサー、バリデータ、トランスフォーマなど)に指示します。

デフォルトでは、JDKはDOMおよびSAXパーサーやXMLスキーマ・バリデータのFSPをオンにします。これらは、プロセッサに対して多数の処理制限を設定します。反対に、JDKではデフォルトでトランスフォーマとXPathのFSPがオフになります。これにより、XSLTおよびXPathの拡張関数が使用可能になります。

ファクトリでsetFeatureメソッドを呼び出し、XMLConstants.FEATURE_SECURE_PROCESSINGtrueまたはfalseのいずれかに設定して、FSPをオンおよびオフにします。たとえば、次のコード・スニペットは、XMLConstants.FEATURE_SECURE_PROCESSINGtrueに設定することにより、ファクトリspfによって作成されるSAXパーサーのFSPをオンにします。

    SAXParserFactory spf = SAXParserFactory.newInstance();
    spf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);

FSPはファクトリを通じてオンまたはオフにすることができますが、Javaセキュリティ・マネージャが存在する場合は常にオンになり、オフにはできません。このため、Java XMLプロセッサは、Javaセキュリティ・マネージャが存在する場合に制限と制約を適用します。ただし、アプリケーションの具体的なニーズに応じて、個々のプロパティを調整できます。JAXPプロパティには、次の2種類があります。

  • 処理の制限: XML処理からの過剰なメモリー消費の防止に役立ちます。
  • 外部アクセスの制限: 外部リソースのフェッチを制御します。

警告:

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

次の項では、これらの2種類のJAXPプロパティについて説明します。

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

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

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

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

JDK XMLプロセッサを使用すると、処理制限を3つの方法で個別に調整できます。

  • 標準のXML APIを使用
  • システム・プロパティを使用
  • jaxp.propertiesファイル内

「JAXPプロパティの使用」および「スコープと順序」を参照してください。

次の表に、JDKでサポートされる処理制限用のJAXPプロパティを示します。これらの各処理制限の値は正の整数です。0以下の値は、制限がないことを示します。値が整数でない場合は、NumericFormatExceptionがスローされます。

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

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

プロパティ名およびシステム・プロパティ 説明 デフォルト値
jdk.xml.elementAttributeLimit 1つの要素で使用できる属性の数を制限します。 10000
jdk.xml.entityExpansionLimit エンティティの展開数を制限します。 64000
jdk.xml.entityReplacementLimit すべてのエンティティ参照のノードの合計数を制限します。 3000000
jdk.xml.maxElementDepth 要素の最大の深さを制限します。 0
jdk.xml.maxGeneralEntitySizeLimit すべての一般エンティティの最大サイズを制限します。 0
jdk.xml.maxOccurLimit "unbounded"以外の値を持つmaxOccurs属性を含むW3C XMLスキーマの文法の構築時に作成できるコンテンツ・モデル・ノードの数を制限します。 5000
jdk.xml.maxParameterEntitySizeLimit 複数のパラメータ・エンティティのネストの結果を含む、パラメータ・エンティティの最大サイズを制限します。 1000000
jdk.xml.maxXMLNameLimit 要素名、属性名、名前空間の接頭辞やURIなど、XML名の最大サイズを制限します。 1000
jdk.xml.totalEntitySizeLimit 一般エンティティとパラメータ・エンティティを含むすべてのエンティティの合計サイズを制限します。サイズはすべてのエンティティの集約として計算されます。 5x10^7
jdk.xml.xpathExprGrpLimit XPath式に含めることができるグループの数を制限します。 10
jdk.xml.xpathExprOpLimit XPath式に含めることができる演算子の数を制限します。 100
jdk.xml.xpathTotalOpLimit XSLスタイルシートのXPath演算子の総数を制限します。 100000

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

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

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

ノート:

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

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

表12-2 ACCESS_EXTERNAL_DTD

属性 説明
名前 http://javax.xml.XMLConstants/property/accessExternalDTD
定義 外部DTDおよび外部エンティティ参照へのアクセスを指定されたプロトコルに制限します。
「外部アクセス制限のJAXPプロパティの値」を参照してください
デフォルト値 all。すべてのプロトコルへの接続が許可されます
システム・プロパティ javax.xml.accessExternalDTD

表12-3 ACCESS_EXTERNAL_SCHEMA

属性 説明
名前 http://javax.xml.XMLConstants/property/accessExternalSchema
定義 schemaLocation属性、import要素およびinclude要素によって設定された外部参照へのアクセスを指定されたプロトコルに制限します。
「外部アクセス制限のJAXPプロパティの値」を参照してください
デフォルト値 all。すべてのプロトコルへの接続が許可されます。
システム・プロパティ javax.xml.accessExternalSchema

表12-4 ACCESS_EXTERNAL_STYLESHEET

属性 説明
名前 http://javax.xml.XMLConstants/property/accessExternalStylesheet
定義 stylesheet処理命令、document関数、importおよびinclude要素によって設定された外部参照へのアクセスを指定されたプロトコルに制限します。
「外部アクセス制限のJAXPプロパティの値」を参照してください
デフォルト値 all。すべてのプロトコルへの接続が許可されます。
システム・プロパティ javax.xml.accessExternalStylesheet

外部アクセス制限の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.propertiesファイルでjavax.xml.accessExternalDTD=allを指定すると、システムは以前のように外部DTDおよびエンティティ参照へのアクセスに対する制限なしで機能できます。

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

スコープと順序

セキュア処理機能の設定のスコープ

XMLプロセッサ(DOM、SAX、スキーマ検証、XSLT、XPathなど)には、セキュア処理機能(FSP)が必要です。

FSPをオンにすると、デフォルトの処理制限(「処理制限用のJAXPプロパティ」を参照)が適用されます。FSPをオフにしても制限は変更されません。

API (たとえばfactory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true))を使用してFSPを"明示的"にオンにすると、外部アクセス制限(「外部アクセス制限用のJAXPプロパティ」を参照)は空の文字列に設定されます。これは、どのプロトコルに対してもアクセス権が付与されないことを意味します。FSPはDOM、SAXおよびスキーマ検証に対してデフォルトでオンになりますが、"明示的"にオンになっているものとしては扱われません。したがって、外部アクセス制限のデフォルト値はallで、これはすべてのプロトコルに対してアクセス権が付与されることを意味します。

Javaセキュリティ・マネージャが存在する場合、FSPはオンになり、オフにはできません。

警告:

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

JAXPプロパティの設定のスコープおよび順序

一般に、より小さいスコープに設定されたJAXPプロパティは、より大きいスコープのJAXPプロパティより優先されます。

  • JAXPファクトリまたはプロセッサを介して指定されるJAXPプロパティは、システム・プロパティ、jaxp.propertiesファイルおよびFSPよりも優先されます。
  • システム・プロパティが設定されている場合は、JDKの1回の起動のみに影響し、デフォルトで設定されているか、jaxp.propertiesファイルで設定されているか、FSPによって設定されている処理制限および外部アクセス制限の値をオーバーライドします。
  • jaxp.propertiesファイルで指定されたプロパティはJDK全体に影響し、デフォルトで設定されているかFSPで設定されている処理制限および外部アクセス制限の値をオーバーライドします。

外部アクセス制限の設定のスコープ

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

  • リゾルバがあり、リゾルバによって返されたソースが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

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

警告:

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

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

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

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

処理制限をいつ使用するか

適用する処理制限および使用する値を決定する場合は、システム・レベルで、アプリケーションで使用可能なメモリー量、および信頼できないソースからの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-5 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です。

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

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

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

警告:

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

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

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

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.propertiesファイルおよびシステム・プロパティによって指定されたコードをオーバーライドし、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");

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

システム・プロパティの使用

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

JDKの起動全体に対してJAXPプロパティを設定するには、コマンド行で対応するシステム・プロパティを設定します。

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");

Javaチュートリアル処理制限のサンプルからの次のコードは、処理制限maxGeneralEntitySizeLimitに対してこれを行う方法を示す別の例です。

    public static final String SP_GENERAL_ENTITY_SIZE_LIMIT =
        "jdk.xml.maxGeneralEntitySizeLimit";

    // Set limits using System property;
    // this setting will affect all processing after it's set
    System.setProperty(SP_GENERAL_ENTITY_SIZE_LIMIT, "2000");

    // Perform some processing here

    // After it is done, clear the property
    System.clearProperty(SP_GENERAL_ENTITY_SIZE_LIMIT);

処理制限の値は整数であることに注意してください。処理制限の値が解析可能な整数でない場合はNumberFormatExceptionがスローされます。メソッドjava.lang.Integer.parseInt(String)を参照してください。

次の例では、アプリケーションの一部の外部スキーマを解決できます。

    // Allow resolution of external schemas
    // This setting will affect all processing after it's set
    System.setProperty("javax.xml.accessExternalSchema", "file, http");

    // Perform some processing here

    // After it's done, clear the property
    System.clearProperty("javax.xml.accessExternalSchema");

jaxp.propertiesファイルの使用

すべてのJDK呼出しに影響するJAXPプロパティを指定する場合は、<java-home>/conf/jaxp.propertiesという名前の構成ファイルを作成し、その中の各行にJAXPプロパティの名前と値のペアを1つずつ指定します。たとえば、次のjaxp.propertiesファイルでは、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.propertiesファイルで次のように外部アクセス制限を設定します。

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

ノート:

  • jaxp.propertiesファイル内の対応するシステム・プロパティを使用します。処理制限システム・プロパティの接頭辞はjdk.xmlです。外部アクセス制限システム・プロパティの接頭辞はjavax.xmlです。
  • 処理制限値は整数です。処理制限の値が解析可能な整数でない場合はNumberFormatExceptionがスローされます。メソッドjava.lang.Integer.parseInt(String)を参照してください。

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.

XMLおよびJAXPプロパティ用のストリーミングAPI

XML (StAX)用のストリーミングAPI、JSR 173では、FSPがサポートされず、外部アクセス制限もサポートされません。一方、JDKのStAX実装では処理制限がサポートされ、JAXPのコンテキストでのStAXでは外部アクセス制限がサポートされます。

StAXおよび処理制限

JDKのStAX実装では、処理制限およびそれらに対応するシステム・プロパティがサポートされます。ただし、FSPはサポートされていないため、FSPをオンまたはオフにすることによってStAXの処理制限をオンまたはオフにすることはできません。処理制限は引き続き「処理制限用のJAXPプロパティ」に説明されているように動作します。

StAXおよび外部アクセスの制限

JDKのStAX実装では、外部アクセス制限に関連するJAXPプロパティがサポートされます。これらの設定はSAXまたはDOMに似ていますが、XMLInputFactoryクラスを使用します。たとえば:

    XMLInputFactory xif = XMLInputFactory.newInstance();
    xif.setProperty(
        "http://javax.xml.XMLConstants/property/accessExternalDTD",
        "file");

互換性を保つために、StAXのプロパティおよび機能は、処理制限および外部アクセス制限のプロパティよりも優先されます。たとえば、SupportDTDプロパティをfalseに設定すると、解析可能になる前に入力ファイルにDTDが含まれる場合に、プログラムによって例外がスローされます。したがって、DTDに対する処理制限および外部アクセス制限は、SupportDTDプロパティをfalseに設定することで無効化されているアプリケーションには影響しません。

拡張関数

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

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

        TransformerFactory tf = TransformerFactory.newInstance();          
        tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
  • enableExtensionFunctionsプロパティをfalseに設定します:

        final static String ENABLE_EXTENSION_FUNCTIONS =
            "http://www.oracle.com/xml/jaxp/properties/enableExtensionFunctions";
        // ...
        TransformerFactory tf = TransformerFactory.newInstance();  
        tf.setFeature(ENABLE_EXTENSION_FUNCTIONS, false);

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

表12-6 enableExtensionFunctions

属性 説明
名前 http://www.oracle.com/xml/jaxp/properties/enableExtensionFunctions
定義 XSLTおよびXPath拡張関数が許可されるかどうかを決定します。
ブール。Trueは拡張関数が許可されることを示します。それ以外の場合はFalseです。
デフォルト値 true
システム・プロパティ jdk.xml.enableExtensionFunctions
導入されたバージョン 7u60

警告:

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

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処理を無効化するには、プロパティSupportDTDXMLInputFactory.setPropertyメソッドで設定します。

    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.propertiesファイル内で、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」を参照してください。

サードパーティ製パーサー

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

表12-7 overrideDefaultParser

属性 説明
名前 jdk.xml.overrideDefaultParser
定義 サードパーティのパーサー実装を使用して、JDKのトランスフォーマバリデータおよびXPath実装のシステムデフォルト・パーサーをオーバーライドできるようにします。このプロパティは、JAXPファクトリ、システム・プロパティまたはjaxp.propertiesファイルを通じて設定できます。
ブール。trueに設定すると、XML変換、XML検証またはXPath操作中にサードパーティ製パーサーの実装でシステムデフォルト実装をオーバーライドできます。falseに設定すると、サードパーティ製パーサー実装の使用が無効になります。値が文字列として指定されている場合、戻り値はBoolean.parseBooleanの値になります。
デフォルト値 false
システム・プロパティ jdk.xml.overrideDefaultParser
導入されたバージョン 6u181、7u171、8u161、9.0.4

次のコード・スニペットは、setFeatureメソッドでjdk.xml.overrideDefaultParserプロパティを設定して、サードパーティ製パーサー(クラスパス上にある場合)を使用するようにファクトリに指示しています。

    static final String JDK_OVERRIDE_PARSER = "jdk.xml.overrideDefaultParser";
    ...
    TransformerFactory tFactory = TransformerFactory.newInstance();
    tFactory.setFeature(JDK_OVERRIDE_PARSER, true);
    ...
    XPathFactory xf = XPathFactory.newInstance();
    xf.setFeature(JDK_OVERRIDE_PARSER, true);
    ...
    SchemaFactory schemaFactory =
        SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
    schemaFactory.setFeature(JDK_OVERRIDE_PARSER, true);
    ...
    Schema schema = schemaFactory.newSchema(new File("mySchema.xsd"));
    Validator validator = schema.newValidator();
    validator.setFeature(JDK_OVERRIDE_PARSER, true);

次のコード・スニペットは、jdk.xml.overrideDefaultParserをシステム・プロパティとして設定しています。

System.setProperty("jdk.xml.overrideDefaultParser", "true"));

jaxp.propertiesファイルに次の行を追加すると、サードパーティ製パーサーを有効にできます。

jdk.xml.overrideDefaultParser=true

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

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

  • セキュア処理機能(FSP)をオンにしてから、特定の要件に従って個々の機能とプロパティを調整します。
  • 処理制限では、アプリケーションが必要とする最大量に対応できるだけの大きさになるように調整します。
  • 外部アクセス制限の場合は、リゾルバの使用を含め、アプリケーションの外部リソースへの依存を軽減または排除してから、これらの制限を強化します。
  • ローカル・カタログを設定し、すべてのXMLプロセッサでカタログAPIを有効にして、アプリケーションの外部リソースへの依存をさらに軽減します。

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

表12-8 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-9 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以降