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時間と大量のメモリーを消費し、最終的にシステムのメモリーが不足する可能性があります。
セキュアなXML処理のためのJAXPの構成
JAXPは、XMLドキュメントの解析、直列化、変換、問合せおよびトラバースを行うためのAPIのセットで構成されます。JAXP APIを参照してください。
JAXPは、ファクトリおよびプロセッサを通じてセキュリティのレイヤーを追加します。ファクトリを通じてJAXPからAPIにアクセスします。これにより、セキュリティ要件に基づいて設定したJAXPプロパティに従ってAPIが構成されます。ファクトリは、それぞれのプロセッサを使用して構成し、インスタンス化します。ファクトリおよびプロセッサを参照してください。
JAXPプロセッサは、JAXPプロパティを使用して構成します。JAXPプロパティは、JAXPファクトリを通じて、システム・プロパティとして、またはJAXP構成ファイルで設定できます。JAXPプロパティを使用した構成を参照してください。
セキュリティ関連のプロパティでは、セキュアなXML処理のためにJAXPを構成する際に設定できるプロパティについて説明します。
コンポジット・プロセッサの項では、バリデータやトランスフォーマなどのコンポジット・プロセッサに対してFEATURE_SECURE_PROCESSING (FSP)を有効にして、コンポジット・プロセッサが使用する内部パーサーに対してもFSPを有効にする方法について説明します。
また、JAXPを使用すると、カスタム・リゾルバおよびカタログを登録することで、外部リソースへの参照を捕捉し、ローカル・リソースで解決できます。これにより、外部リソースの読取りとアクセスの必要がなくなるため、潜在的なリスクのソースを除去するのに役立ちます。リゾルバおよびカタログの使用を参照してください。
JAXP API
JAXPは、XML処理に不可欠なXMLの技術および標準を構築したAPIのセットで構成されます。これには、次のAPIが含まれています:
- 解析: JAXP解析API (javax.xml.parsersパッケージ)は、Document Object Model (DOM) (org.w3c.domパッケージ)と、Simple API for XML解析(SAX) (org.xml.saxパッケージ)をベースとしています
- Streaming API for XML (StAX) (javax.xml.streamパッケージ)
- 直列化: StAXおよびExtensible Stylesheet Language Transformation (XSLT) (javax.xml.transformパッケージ)
- 変換: JAXP変換API (javax.xml.transformパッケージ)およびXSLT (Extensible Stylesheet Language Transformations)
- XMLドキュメントの問合せおよびトラバース: XMLパス言語(XPath) API (javax.xml.xpathパッケージ)
- 外部リソースの解決: XMLカタログAPI (javax.xml.catalogパッケージ)
ファクトリおよびプロセッサ
ファクトリは、各JAXP APIのエントリ・ポイントです。これらは、アプリケーションがプロセッサを作成する前にJAXPプロパティをプログラムで設定できるようにするメソッドを提供します。ファクトリはJAXP検索メカニズムもサポートしており、JDK実装ではなくサードパーティ実装を使用してアプリケーションをデプロイできます。
プロセッサは、それぞれの領域で処理を制御および実行するパーサー(またはリーダー)、シリアライザ(またはライター)、バリデータおよびトランスフォーマを集約したものです。ファクトリは、対応するファクトリを構成し、インスタンス化します。たとえば、DocumentBuilderFactoryおよびSAXParserFactoryファクトリを使用して、それぞれDocumentBuilderおよびSAXParserプロセッサを構成し、インスタンス化します。
JAXPプロパティを使用した構成
JAXPプロセッサは、JAXPプロパティを使用して構成します。次に、JAXPプロパティを設定する方法を、優先順位の高いものから低いものの順に示します。たとえば、ファクトリを通じてJAXPプロパティの値を設定すると、別の方法で設定された他の値がオーバーライドされます。
- JAXPファクトリを使用したJAXPプロパティの設定: コード内のJAXPファクトリを通じてJAXPプロパティを設定できます。
- システム・プロパティとしてのJAXPプロパティの設定: JAXPプロパティをシステム・プロパティのように設定するには、コマンドラインで次の構文を使用して値を設定します:
-D<property name>=<property value>システム・プロパティの値は、メソッドSystem.setProperty(String key, String name)またはSystem.setProperties(Properties)を使用して設定することもできます。
- JAXP構成ファイルでのJAXPプロパティの設定: JAXPプロパティは、
<java-home>/conf/jaxp.propertiesという名前のJAXP構成ファイルで設定できます。
すべてのJAXPプロパティが、これらすべての方法によって設定できるわけではありません。特定のJAXPプロパティを設定できるメソッドを確認するには、java.xmlモジュールのサマリーを参照してください。
次のいずれかの方法で特定のJAXPプロパティを設定していない場合、JavaランタイムはデフォルトのJAXPプロパティ・ファイルで指定された値を使用します。このファイルにプロパティが存在しない場合、Javaランタイムはそのデフォルト値を使用します。ただし、FEATURE_SECURE_PROCESSING (FSP)がオンの場合、Javaランタイムで使用する値はより限定的になります(該当する場合)。詳細は、java.xmlモジュールのサマリーにある実装固有の機能とプロパティの表を参照してください。
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("http://www.oracle.com/xml/jaxp/properties/entityExpansionLimit", "2000");
dbf.setAttribute("http://www.oracle.com/xml/jaxp/properties/maxGeneralEntitySizeLimit", "100000");
dbf.setAttribute("http://www.oracle.com/xml/jaxp/properties/maxParameterEntitySizeLimit", "10000");
dbf.setAttribute("http://www.oracle.com/xml/jaxp/properties/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プロパティを他の手段で設定するかどうかに関係なく、アプリケーションの動作が同じようになります。
システム・プロパティとしての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");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プロパティはJDK実装に固有ですが、外部アクセス・プロパティ(EAP)に関連するプロパティは標準プロパティです。JAXP構成ファイルでのJAXPプロパティの設定
すべての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, httpXMLプロセッサによる外部接続を許可しない場合は、すべての外部アクセス・プロパティ(EAP)をfileのみに設定できます。
javax.xml.accessExternalDTD=file
javax.xml.accessExternalSchema=file
javax.xml.accessExternalStylesheet=fileアプリケーションがXMLプロセッサを通じて外部ファイルを誤って読み取ることを防ぐには、jaxp.propertiesファイルで次のようにEAPを設定します。
javax.xml.accessExternalDTD=""
javax.xml.accessExternalSchema=""
javax.xml.accessExternalStylesheet=""ノート:
jaxp.propertiesファイル内の対応するシステム・プロパティを使用します。処理制限に対応するシステム・プロパティの接頭辞はjdk.xmlです。EAPに対応するシステムプロパティの接頭辞はjavax.xmlです。- 処理制限値は整数です。処理制限の値が解析可能な整数でない場合はNumberFormatExceptionがスローされます。メソッドjava.lang.Integer.parseInt(String)を参照してください。
JAXPプロパティの設定のスコープおよび順序
JAXPプロパティは、APIメソッド、システム・プロパティ、JAXP構成ファイルなど、複数の方法で設定できます。明示的に設定しない場合、FEATURE_SECURE_PROCESSING (FSP)を有効にすると、デフォルト値またはより制限された値で初期化されます。プロパティの優先順位は、高い順に次のとおりです:
- ファクトリまたはプロセッサ用のAPI
- システム・プロパティ
- JAXP構成ファイル
<java_home>/conf/jaxp.properties - JAXPプロパティのデフォルト値。FSPがtrueの場合、デフォルト値はXMLを安全に処理するように設定されます
次に、CatalogFeaturesクラスのRESOLVEプロパティを例として使用して、これらのルールの適用方法を示します:
-
ファクトリまたはプロセッサAPIで指定されたプロパティの優先順位が最も高くなります。次のコードは、他の構成ソースの設定に関係なく、RESOLVEプロパティを効果的に
strictに設定します。DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setAttribute(CatalogFeatures.Feature.RESOLVE.getPropertyName(), "strict"); -
プロパティが前の例のようにファクトリによって設定されていない場合は、システム・プロパティ設定が有効になります。次のコマンドラインの例は、アプリケーション
myAppのRESOLVEプロパティをcontinueに設定します。java -Djavax.xml.catalog.resolve=continue myApp -
プロパティがファクトリによって、またはシステム・プロパティで設定されていない場合は、JAXP構成ファイル
<java_home>/conf/jaxp.propertiesの設定が有効になります。次のエントリは、RESOLVEプロパティをcontinueに設定します。javax.xml.catalog.resolve=continue -
RESOLVEプロパティの値がどこにも設定されていない場合、デフォルト値の
strictに解決されます。
セキュリティ関連のプロパティ
次の項では、セキュアなXML処理のためにJAXPを構成する際に設定できるプロパティについて説明します:
2種類のJAXPのセキュリティ関連プロパティがあります:
- API定義プロパティ: これらは、ファクトリまたはパーサーの
setAttribute(String, Object)またはsetProperty(String, Object)メソッドで設定した値を持つ、Java SE APIの一部である定数フィールド値です。これらのフィールドの一部には、コマンドラインまたはJAXP構成ファイルで設定できる、対応するシステム・プロパティがあります。 - JDK固有のプロパティ: これらは、JAXPパーサーまたはファクトリ、コマンドラインまたはJAXP構成ファイルで設定するシステム・プロパティです。これらの一部はシステム・プロパティではありません。つまり、コマンドラインで値を設定できません:
API定義プロパティ
FEATURE_SECURE_PROCESSINGセキュリティ・ディレクティブ
FEATURE_SECURE_PROCESSING (FSP)セキュリティ・ディレクティブは、XMLドキュメントを処理するためのセキュリティ制限の有効化を通知します。JAXP APIによって定義され、JAXP実装からセキュア・モードをリクエストするための標準メカニズムを提供します。JAXPファクトリを介してtrueに設定されている場合、パーサーなどのJAXPプロセッサに、プロセッサのセキュリティ・モデルに基づいて様々な制限を適用するように指示します。たとえば:
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);また、FEATURE_SECURE_PROCESSINGがtrueに設定されている場合、JDKは外部アクセス・プロパティ(EAP)およびJDK固有のプロパティを介してセキュリティ制限をアクティブ化します。
デフォルトでは、JDKはSAX、DOMおよび検証のFSPをオンにします。
セキュリティ・マネージャが存在する場合は、JAXPセキュリティ処理が自動的にオンになります。存在しない場合は、JAXPセキュリティ処理がデフォルトで無効になります。
外部アクセス・プロパティ
外部アクセス・プロパティ(EAP)を対応するシステム・プロパティとともに使用すると、外部接続を規制できます。
EAPを使用すると、許可できるまたは許可できない外部接続のタイプを指定できます。プロパティ値は、プロトコルのリストです。JAXPプロセッサは、プロトコルをリスト内のプロトコルと照合することによって、特定の外部接続が許可されているかどうかをチェックします。プロセッサは、リスト上にある場合は接続を確立しようとし、そうでない場合は拒否しようとします。これらのJAXPプロパティをカスタム・リゾルバおよびカタログAPIとともに使用して(「リゾルバおよびカタログの使用」を参照)、ローカル・リソースを拒否および解決することにより、外部接続のリスクを軽減します。
ノート:
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true)などのAPIを通じてセキュア処理機能(FSP)を明示的にオンにし、すべての外部接続を無効にします。
EAPは、javax.xml.XMLConstantsで次のように定義されます:
- javax.xml.XMLConstants.ACCESS_EXTERNAL_DTD
- javax.xml.XMLConstants.ACCESS_EXTERNAL_SCHEMA
- javax.xml.XMLConstants.ACCESS_EXTERNAL_STYLESHEET
表12-1 ACCESS_EXTERNAL_DTD
| 属性 | 説明 |
|---|---|
| 名前 | http://javax.xml.XMLConstants/property/accessExternalDTD |
| 定義 | 外部DTDおよび外部エンティティ参照へのアクセスを指定されたプロトコルに制限します。 |
| 値 | 「EAPの値」を参照してください |
| デフォルト値 | all。すべてのプロトコルへの接続が許可されます |
| システム・プロパティ | javax.xml.accessExternalDTD |
表12-2 ACCESS_EXTERNAL_SCHEMA
| 属性 | 説明 |
|---|---|
| 名前 | http://javax.xml.XMLConstants/property/accessExternalSchema |
| 定義 | schemaLocation属性、import要素およびinclude要素によって設定された外部参照へのアクセスを指定されたプロトコルに制限します。
|
| 値 | 「EAPの値」を参照してください |
| デフォルト値 | all。すべてのプロトコルへの接続が許可されます。 |
| システム・プロパティ | javax.xml.accessExternalSchema |
表12-3 ACCESS_EXTERNAL_STYLESHEET
| 属性 | 説明 |
|---|---|
| 名前 | http://javax.xml.XMLConstants/property/accessExternalStylesheet |
| 定義 | stylesheet処理命令、document関数、importおよびinclude要素によって設定された外部参照へのアクセスを指定されたプロトコルに制限します。
|
| 値 | 「EAPの値」を参照してください |
| デフォルト値 | all。すべてのプロトコルへの接続が許可されます。 |
| システム・プロパティ | javax.xml.accessExternalStylesheet |
EAPの値
すべてのEAPの値は同じフォーマットです:
-
値: カンマで区切られたプロトコルのリスト。プロトコルは、URIのスキーム部分であり、JARプロトコルの場合は
jarに、コロンで区切られたスキーム部分が付け加えられたものになります。スキームは次のように定義されます。scheme = alpha *( alpha | digit | "+" | "-" | "." )ここで、
JARプロトコルは、alpha=a-zおよびA-Zです。jar[:scheme]として定義されますプロトコルでは大文字と小文字が区別されません。値に含まれる、Character.isSpaceCharで定義された空白はすべて無視されます。プロトコルの例として、
file、httpおよびjar:fileがあります。 -
デフォルト値: デフォルト値は実装固有です。JDKの場合、デフォルト値は
allで、すべてのプロトコルに対するアクセス権を付与します。 -
すべてのアクセスの許可: キーワード
allは、すべてのプロトコルに対するアクセス権を付与します。たとえば、jaxp.propertiesファイルでjavax.xml.accessExternalDTD=allを指定すると、システムは以前のように外部DTDおよびエンティティ参照へのアクセスに対する制限なしで機能できます。 -
アクセスの拒否: 空の文字列(
"")は、どのプロトコルに対してもアクセス権が付与されていないことを意味します。たとえば、jaxp.propertiesファイルにjavax.xml.accessExternalDTD=""を指定すると、JAXPプロセッサは外部接続を拒否します。
外部アクセス・プロパティをいつ使用するか
XMLプロセッサは、デフォルトで、XMLソースで参照される外部リソースへの接続および読取りを試行します。これにより、アプリケーションおよびシステムは、外部接続によって発生するリスクに晒される可能性があることに注意してください。そのため、アプリケーションではEAPを使用した外部接続の制限を検討することをお薦めします。
信頼できるXMLドキュメントのみを処理する内部アプリケーションおよびシステムでは、これらのEAPが不要な場合があります。外部接続を規制するためにJavaセキュリティ・マネージャに依存するアプリケーションおよびシステムでも、それらが不要な場合があります。ただし、EAPはXMLプロセッサに固有であり、プロセスの最上位レイヤーにあることに注意してください。つまり、プロセッサは接続を行う前にこれらのEAPをチェックします。したがって、外部接続リスクに対する、より直接的な追加の保護として機能します。
EAPをカスタムのリゾルバおよびカタログ(「リゾルバおよびカタログの使用」を参照)とともに使用すると、外部接続を効果的に管理し、リスクを軽減できます。
信頼できるソースを含む信頼できる環境であっても、EAPとリゾルバの両方を使用して外部ソースへの依存を最小限にすることをお薦めします。
JAXPプロパティの優先順位および外部アクセス・プロパティ
EAPは、次のような状況で制限しようとする関連コンストラクトには影響しません。
-
リゾルバがあり、リゾルバによって返されたソースがnullではない場合: これは、SAXおよびDOMパーサーで設定できるエンティティ・リゾルバ、StAXパーサー上のXMLリゾルバ、SchemaFactory上のLSResourceResolver、Validatorまたは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
JDK固有のプロパティ
処理制限用のJAXPプロパティ
XML処理は、メモリー集中型の操作である場合があります。信頼できないソースからのXML、XSDおよびXSLを受け入れるアプリケーションでは特に、処理制限用のJAXPプロパティを使用して、過剰なメモリー消費を回避するステップをとる必要があります。
アプリケーションの要件およびオペレーティング環境を評価して、システム構成の許容可能な処理制限を判断し、それに応じてこれらの制限を設定します。たとえば、サイズ関連の制限を使用して、不適切なXMLソースによる大量のメモリー消費を防止します。許容レベルでのメモリー消費をアプリケーションで制御できるようにするには、EntityExpansionLimitを使用します。
JDK XMLパーサーは、デフォルトで処理制限を監視します。DOMおよびSAXパーサーでは、FSPがデフォルトでオンになっているため、制限がオンになります。また、StAXパーサーは、FSPをサポートしていなくても、デフォルトで処理制限を遵守します。
JDK XMLプロセッサを使用すると、処理制限を3つの方法で個別に調整できます。
- 標準のXML APIを使用
- システム・プロパティを使用
jaxp.propertiesファイル内
JAXPプロパティを使用した構成を参照してください。
次の表に、JDKでサポートされる処理制限用のJAXPプロパティを示します。
表12-4 elementAttributeLimit
| 属性 | 説明 |
|---|---|
| 名前 | http://www.oracle.com/xml/jaxp/properties/elementAttributeLimit |
| 定義 | 1つの要素で使用できる属性の数を制限します。 |
| 値 | 正の整数。0以下の値は、制限がないことを示します。値が整数でない場合は、NumericFormatExceptionがスローされます。
|
| デフォルト値 | 10000 |
| システム・プロパティ | jdk.xml.elementAttributeLimit |
| 導入されたバージョン | 7u45、8 |
表12-5 entityExpansionLimit
| 属性 | 説明 |
|---|---|
| 名前 | http://www.oracle.com/xml/jaxp/properties/entityExpansionLimit |
| 定義 | エンティティの展開数を制限します。 |
| 値 | 正の整数。0以下の値は、制限がないことを示します。値が整数でない場合は、NumericFormatExceptionがスローされます。
|
| デフォルト値 | 64000 |
| システム・プロパティ | jdk.xml.entityExpansionLimit |
| 導入されたバージョン | 7u45、8 |
表12-6 entityReplacementLimit
| 属性 | 説明 |
|---|---|
| 名前 | http://www.oracle.com/xml/jaxp/properties/entityReplacementLimit |
| 定義 | すべてのエンティティ参照のノードの合計数を制限します。 |
| 値 | 正の整数。0以下の値は、制限がないことを示します。値が整数でない場合は、NumericFormatExceptionがスローされます。
|
| デフォルト値 | 3000000 |
| システム・プロパティ | jdk.xml.entityReplacementLimit |
| 導入されたバージョン | 7u111、8u101 |
表12-7 maxElementDepth
| 属性 | 説明 |
|---|---|
| 名前 | http://www.oracle.com/xml/jaxp/properties/maxElementDepth |
| 定義 | 要素の最大の深さを制限します。 |
| 値 | 正の整数。0以下の値は、制限がないことを示します。値が整数でない場合は、NumericFormatExceptionがスローされます。
|
| デフォルト値 | 0 |
| システム・プロパティ | jdk.xml.maxElementDepth |
| 導入されたバージョン | 7u65、8u11 |
表12-8 maxGeneralEntitySizeLimit
| 属性 | 説明 |
|---|---|
| 名前 | http://www.oracle.com/xml/jaxp/properties/maxGeneralEntitySizeLimit |
| 定義 | すべての一般エンティティの最大サイズを制限します。 |
| 値 | 正の整数。0以下の値は、制限がないことを示します。値が整数でない場合は、NumericFormatExceptionがスローされます。
|
| デフォルト値 | 0 |
| システム・プロパティ | jdk.xml.maxGeneralEntitySizeLimit |
| 導入されたバージョン | 7u45、8 |
表12-9 maxOccurLimit
| 属性 | 説明 |
|---|---|
| 名前 | http://www.oracle.com/xml/jaxp/properties/maxOccurLimit |
| 定義 | "unbounded"以外の値を持つmaxOccurs属性を含むW3C XMLスキーマの文法の構築時に作成できるコンテンツ・モデル・ノードの数を制限します。
|
| 値 | 正の整数。0以下の値は、制限がないことを示します。値が整数でない場合は、NumericFormatExceptionがスローされます。
|
| デフォルト値 | 5000 |
| システム・プロパティ | jdk.xml.maxOccurLimit |
| 導入されたバージョン | 7u45、8 |
表12-10 maxParameterEntitySizeLimit
| 属性 | 説明 |
|---|---|
| 名前 | http://www.oracle.com/xml/jaxp/properties/maxParameterEntitySizeLimit |
| 定義 | 複数のパラメータ・エンティティのネストの結果を含む、パラメータ・エンティティの最大サイズを制限します。 |
| 値 | 正の整数。0以下の値は、制限がないことを示します。値が整数でない場合は、NumericFormatExceptionがスローされます。
|
| デフォルト値 | 1000000 |
| システム・プロパティ | jdk.xml.maxParameterEntitySizeLimit |
| 導入されたバージョン | 7u45、8 |
表12-11 maxXMLNameLimit
| 属性 | 説明 |
|---|---|
| 名前 | http://www.oracle.com/xml/jaxp/properties/maxXMLNameLimit |
| 定義 | 要素名、属性名、名前空間の接頭辞やURIなど、XML名の最大サイズを制限します。 |
| 値 | 正の整数。0以下の値は、制限がないことを示します。値が整数でない場合は、NumericFormatExceptionがスローされます。
|
| デフォルト値 | 1000 |
| システム・プロパティ | jdk.xml.maxXMLNameLimit |
| 導入されたバージョン | 7u91、8u65 |
表12-12 totalEntitySizeLimit
| 属性 | 説明 |
|---|---|
| 名前 | http://www.oracle.com/xml/jaxp/properties/totalEntitySizeLimit |
| 定義 | 一般エンティティとパラメータ・エンティティを含むすべてのエンティティの合計サイズを制限します。サイズはすべてのエンティティの集約として計算されます。 |
| 値 | 正の整数。0以下の値は、制限がないことを示します。値が整数でない場合は、NumericFormatExceptionがスローされます。
|
| デフォルト値 | 5x10^7 |
| システム・プロパティ | jdk.xml.totalEntitySizeLimit |
| 導入されたバージョン | 7u45、8 |
レガシー・システム・プロパティ
これらのプロパティはJDK 5.0および6で導入されたもので、下位互換性のために引き続きサポートされます。
表12-13 処理制限に関連するレガシー・システム・プロパティ
| システム・プロパティ | 導入されたバージョン | 新規システム・プロパティ |
|---|---|---|
entityExpansionLimit |
1.5 | jdk.xml.entityExpansionLimit |
elementAttributeLimit |
1.5 | jdk.xml.elementAttributeLimit |
maxOccurLimit |
1.6 | jdk.xml.maxOccur |
FEATURE_SECURE_PROCESSINGのデフォルトの制限
次の表では、FEATURE_SECURE_PROCESSING (FSP)が有効な場合に無効になるXML関連ファクトリ・クラスと設定される処理制限について説明します。
表12-14 XML関連ファクトリ・クラスでFSPによって設定されるデフォルトの制限
| XML関連ファクトリ・クラス | 有効? | 処理制限 |
|---|---|---|
| DocumentBuilderFactory | true | jdk.xml.entityExpansionLimit = 64000
|
| SAXParserFactory | true | jdk.xml.entityExpansionLimit = 64000
|
| SchemaFactory | true | jdk.xml.maxOccurLimit = 5000
|
| TransformerFactory | false | 拡張関数が無効です |
| XPathFactory | false | 拡張関数が無効です |
エンティティ展開の制限
システム・プロパティjdk.xml.entityExpansionLimitまたはパーサー・プロパティhttp://apache.org/xml/properties/entity-expansion-limitを設定して、エンティティ展開の数を制限します。どちらのプロパティもjava.lang.Integer値を受け入れます。エンティティ展開の上限に達すると、パーサーは致命的なエラーをスローします。デフォルトでは、entityExpansionLimitは64,000に設定されます。
次のコマンド行の例では、エンティティ展開制限が10,000に設定されます。
java -DentityExpansionLimit=10000 MyApp 次のコード例では、エンティティ展開制限が10,000に設定されます。
System.setProperty("jdk.xml.entityExpansionLimit","10000");次のコード例では、パーサー・プロパティhttp://apache.org/xml/properties/entity-expansion-limitが10,000に設定されます。
DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance();
dfactory.setAttribute(
"http://apache.org/xml/properties/entity-expansion-limit",
new Integer("10000"));
DocumentBuilder docBuilder = dbFactory.newDocumentBuilder();要素属性数の制限
システム・プロパティjdk.xml.elementAttributeLimitを設定するか、パーサー・プロパティhttp://apache.org/xml/properties/elementAttributeLimitを設定して、要素内の属性の数を制限します。どちらのプロパティもInteger値を受け入れます。デフォルトでは、jdk.xml.elementAttributeLimitは10,000に設定されます。パーサー・プロパティhttp://apache.org/xml/properties/elementAttributeLimitが設定されると、システム・プロパティがオーバーライドされます。要素内の属性数が制限を超えると、パーサーは致命的エラーをスローします。
次のコマンド行の例では、要素属性制限が20に設定されます。
java -Djdk.xml.elementAttributeLimit=20 MyApp次のコード例では、要素属性制限が20に設定されます。
System.setProperty("jdk.xml.elementAttributeLimit","20");次のコード例では、パーサー・プロパティhttp://apache.org/xml/properties/entity-expansion-limitが20に設定されます。
DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance();
dfactory.setAttribute(
"http://apache.org/xml/properties/elementAttributeLimit",
new Integer(20));
DocumentBuilder docBuilder = dbFactory.newDocumentBuilder();maxOccursを含むコンストラクトにより作成されるノード数の制限
xsd:sequenceなどの構成では、検証パーサーはmaxOccursオカレンス・インジケータの値に比例した領域(メモリー)を使用できます。これによってVMのメモリーが不足したり、非常に長時間実行される場合があります。この動作を悪用する潜在的攻撃を防ぐには、次のようにファクトリのセキュアな処理を有効にします。
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE);xsd:elementおよびxsd:anyの場合、検証パーサーは一定量の領域を使用します。これはmaxOccursオカレンス・インジケータの値とは関係ありません。
jdk.xml.maxOccurLimitのデフォルト値は5000です。このシステム・プロパティは、"unbounded"以外の値を持つmaxOccursオカレンス・インジケータを含むW3C XMLスキーマの文法の構築時に作成できるコンテンツ・モデル・ノードの数を制限します。
処理制限をいつ使用するか
適用する処理制限および使用する値を決定する場合は、システム・レベルで、アプリケーションで使用可能なメモリー量、および信頼できないソースからの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-15 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です。
拡張関数
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-16 enableExtensionFunctions
| 属性 | 説明 |
|---|---|
| 名前 | http://www.oracle.com/xml/jaxp/properties/enableExtensionFunctions |
| 定義 | XSLTおよびXPath拡張関数が許可されるかどうかを決定します。 |
| 値 | ブール。Trueは拡張関数が許可されることを示します。それ以外の場合はFalseです。 |
| デフォルト値 | true |
| システム・プロパティ | jdk.xml.enableExtensionFunctions |
| 導入されたバージョン | 7u60 |
サードパーティ製パーサー
JDKでは、クラスパスにサードパーティ製のパーサーが存在する場合でも、常にシステムデフォルト・パーサーが使用されます。JDKのシステムデフォルト・パーサーをオーバーライドするには、jdk.xml.overrideDefaultParserプロパティをtrueに設定します。
表12-17 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=trueDTD処理の無効化
アプリケーションで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処理を無効化するには、プロパティSupportDTDをXMLInputFactory.setPropertyメソッドで設定します。
XMLInputFactory xif = XMLInputFactory.newInstance();
xif.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);
コンポジット・プロセッサ
バリデータ、トランスフォーマ、XPathプロセッサなどのコンポジット・プロセッサは、内部的に作成されたパーサーを使用して、DOMSourceまたはDocumentではない場合にソースを読み取ります。SchemeFactory、TransformerFactory、XPathFactoryなどのファクトリを介してFEATURE_SECURE_PROCESSING (FSP)をオンにすると、内部パーサー・インスタンスでもオンになります。これは、内部パーサーがSAXParserFactoryまたはDocumentBuilderFactoryで作成されたパーサーと同じように動作することを意味します。
たとえば、次のコードはFSPを使用してXPathFactoryのインスタンスを作成します:
XPathFactory xf = XPathFactory.newInstance();
xf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true); このプロセスにより、RAW XMLソースの評価に使用される場合など、XPathプロセッサで必要な内部パーサーに対してもFSPがオンになります。結果として、パーサーによって定義された制限が適用されます。たとえば、カタログまたはリゾルバによって解決されない外部参照がXMLソースに含まれている場合、FSPが明示的にオンになっているため、「外部アクセス・プロパティ」の説明に従って拒否されます。
リゾルバおよびカタログの使用
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 Javaコア・ライブラリ開発者ガイドのXMLカタログAPIを参照してください。
XMLカタログAPIを使用して、外部リソースをCatalogResolverインタフェースで解決し、JDK XMLプロセッサ上でカタログを有効化します。
カタログ・リゾルバ
カタログ・オブジェクトとして構成されたローカル・リソースで外部参照を置き換えるカスタム・リゾルバとしてCatalogResolverを使用できます。「Java XMLリゾルバ」で説明されているように、EntityResolver、XMLResolver、URIResolverまたはLSResourceResolverのかわりにCatalogResolverをファクトリまたはプロセッサに登録できます。次のコード・スニペットでは、CatalogResolverがSAXParserFactoryにEntityResolverとして登録されます。
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 Javaコア・ライブラリ開発者ガイドの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: JAXP00010001ElementAttributeLimit: JAXP00010002MaxEntitySizeLimit: JAXP00010003TotalEntitySizeLimit: JAXP00010004MaxXMLNameLimit: JAXP00010005maxElementDepth: JAXP00010006EntityReplacementLimit: JAXP00010007
エラー・コードの形式は、次のとおりです。
"JAXP" + components (two digits) + error category (two digits) + sequence numberしたがって、コードJAXP00010001は、JAXPベース・パーサーのセキュリティ制限EntityExpansionLimitを表します。
EAPによって設定された制限が原因で外部リソースへのアクセスが拒否された場合、次の形式でエラーとともに例外がスローされます。
[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_DTDJAXPプロパティは次のように設定されます。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のプロパティと機能の構成に関する一般的な推奨事項を次に示します。
- FSPをオンにしてから、特定の要件に従って個々の機能とプロパティを調整します。
- 処理制限では、アプリケーションが必要とする最大量に対応できるだけの大きさになるように調整します。
- EAPの場合は、リゾルバの使用を含め、アプリケーションの外部リソースへの依存を軽減または排除してから、これらの制限を強化します。
- ローカル・カタログを設定し、すべてのXMLプロセッサでカタログAPIを有効にして、アプリケーションの外部リソースへの依存をさらに軽減します。
付録A: Java API for XML Processingの用語および定義の用語集
表12-18 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実装専用プロパティ |
| EAP | 外部アクセス・プロパティ |
| 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-19 JavaおよびJDK XMLの機能とプロパティの命名規則
| スコープ | APIプロパティ接頭辞 | システム・プロパティ接頭辞 | Java SEおよびJDKバージョン |
|---|---|---|---|
| Java SE |
|
javax.xml |
1.4以降 |
| JDK | http://www.oracle.com/xml/jaxp/properties |
jdk.xml |
7以降 |
| JDK | jdk.xml |
jdk.xml |
9以降 |