JDKおよびJava XML APIは、アプリケーションがXML関連の攻撃によって悪用されないようにするのに役立つ様々な手段とツールで何年にもわたり改善されてきました。 このガイドでは、Java API for XML Processing (JAXP)のセキュア処理機能を使用してアプリケーションおよびシステムを保護する方法を示します。
XML処理は、アプリケーションを一定の脆弱性に晒すことがあります。 最も顕著で有名な攻撃は、XML外部エンティティ(XXE)インジェクション攻撃と指数関数的エンティティ展開攻撃で、XML爆弾やBillion laughs攻撃とも呼ばれます。 これらの攻撃は、そのサービスを拒否することでシステムの重大な破損を引き起こしたり、さらに悪いことに機密データの喪失につながったりすることがあります。
アプリケーションの要件およびオペレーティング環境を評価して、潜在的な脅威のレベル(たとえば、信頼できないXMLソースにアプリケーションが公開されているかどうか、またはどの程度公開されているか)を評価する必要があります。
XML、XMLスキーマおよびXSLT標準では、外部リソースを参照するシステム識別子を通じてXMLドキュメントに外部コンテンツを埋め込むことができる構造をいくつか定義します。 一般に、XMLプロセッサは、これらの外部リソースのほぼすべてを解決および取得します。外部リソースの挿入をサポートするコンストラクトのリストは、「XML、スキーマおよびXSLT標準でサポートされる外部リソース」を参照してください。 また、一部のコンストラクトでは、外部関数を通じてアプリケーションを実行できます。 XML外部エンティティ(XXE)インジェクション攻撃は、解決、取得または実行できる外部リソースの制限によって保護されていないXMLプロセッサを悪用します。 これにより、パスワードなどの機密データが開示されたり、コードを任意に実行できるようになったりすることがあります。
XML、スキーマおよびXSLT標準では、外部リソースを必要とする次のコンストラクトがサポートされています。 JDK XMLプロセッサのデフォルトの動作では、接続を作成し、指定された外部リソースをフェッチします。
外部DTD: 外部ドキュメント・タイプ定義(DTD)を参照します。たとえば:
<!DOCTYPE root_element SYSTEM "url">
外部エンティティ参照: 外部データを参照します。次に構文を示します。
<!ENTITYname
SYSTEM "url
">
一般エンティティ参照。たとえば:
<?xml version="1.0" standalone="no" ?> <!DOCTYPE doc [<!ENTITY otherFile SYSTEM "otherFile.xml">]> <doc> <a> <b>&otherFile;</b> </a> </doc>
外部パラメータ・エンティティ: 次に構文を示します。
<!ENTITY %name
SYSTEMuri
>
次に、例を示します。
<?xml version="1.0" standalone="no"?> <!DOCTYPE doc [ <!ENTITY % ent1 SYSTEM "http://www.example.com/student.dtd"> %ent1; ]>
<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>
<xsl:include href="include
.xsl"/>
xml-stylesheet
処理命令: XML文書にスタイル・シートを含めるために使用します。次に例を示します:
<?xml-stylesheet href="include.xsl" type="text/xsl"?>
document()
関数: 外部XML文書内のノードへのアクセスに使用されます。次に例を示します:
<xsl:variable 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時間と大量のメモリーを消費し、最終的にシステムのメモリーが不足する可能性があります。
javax.xml.XMLConstants.FEATURE_SECURE_PROCESSING
と定義されているセキュア処理(FSP)の機能が、XML処理を保護するための中心的なメカニズムです。 パーサーやトランスフォーマなどのXMLプロセッサに、XMLを安全に処理するよう指示します。
デフォルトでは、JDKはDOMおよびSAXパーサーやXMLスキーマ・バリデータのFSPをオンにします。これらは、プロセッサに対して多数の処理制限を設定します。 反対に、JDKではデフォルトでトランスフォーマとXPathのFSPがオフになります。これにより、XSLTおよびXPathの拡張関数が使用可能になります。
ファクトリのsetFeatureメソッドをコールし、XMLConstants.FEATURE_SECURE_PROCESSING
をtrue
またはfalse
に設定して、FSPのオンとオフを切り替えます。 たとえば、次のコード・スニペットは、XMLConstants.FEATURE_SECURE_PROCESSING
をtrue
に設定することでファクトリspf
によって作成されたSAXパーサーのFSPをオンにします:
SAXParserFactory spf = SAXParserFactory.newInstance(); spf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
FSPはファクトリを通じてオンまたはオフにすることができますが、Javaセキュリティ・マネージャが存在する場合は常にオンになり、オフにはできません。 このため、Java XMLプロセッサは、Javaセキュリティ・マネージャが存在する場合に制限と制約を適用します。 ただし、アプリケーションの具体的なニーズに応じて、個々のプロパティを調整できます。 JAXPプロパティには、次の2種類があります。
次の項では、これらの2種類のJAXPプロパティについて説明します。
XML処理は、メモリー集中型の操作である場合があります。 信頼できないソースからのXML、XSDおよびXSLを受け入れるアプリケーションでは特に、処理制限用のJAXPプロパティを使用して、過剰なメモリー消費を回避するステップをとる必要があります。
アプリケーションの要件およびオペレーティング環境を評価して、システム構成の許容可能な処理制限を判断し、それに応じてこれらの制限を設定します。 たとえば、サイズ関連の制限を使用して、不適切なXMLソースによる大量のメモリー消費を防止します。 EntityExpansionLimit
を使用して、アプリケーションが許容可能なレベルでメモリー消費を制御できるようにします。
JDK XMLパーサーは、デフォルトで処理制限を監視します。 DOMおよびSAXパーサーでは、セキュア処理機能(FSP)がデフォルトでオンになっているため、制限がオンになります。 また、StAXパーサーは、FSPをサポートしていなくても、デフォルトで処理制限を遵守します。
JDK XMLプロセッサを使用すると、処理制限を3つの方法で個別に調整できます。
jaxp.properties
ファイル内「JAXPプロパティの使用」および「スコープと順序」を参照してください。
次の表に、JDKでサポートされる処理制限用のJAXPプロパティを示します。
これらのプロパティはJDK 5.0および6で導入されたもので、下位互換性のために引き続きサポートされます。
システム・プロパティ | 導入されたバージョン | 新規システム・プロパティ |
---|---|---|
entityExpansionLimit |
1.5 |
jdk.xml.entityExpansionLimit |
elementAttributeLimit |
1.5 |
jdk.xml.elementAttributeLimit |
maxOccurLimit |
1.6 |
jdk.xml.maxOccur |
外部アクセス制限用のJAXPプロパティを対応するシステム・プロパティとともに使用すると、外部接続を規制できます。
外部アクセス制限を使用すると、許可できるまたは許可できない外部接続のタイプを指定できます。 プロパティ値は、プロトコルのリストです。 JAXPプロセッサは、プロトコルをリスト内のプロトコルと照合することによって、特定の外部接続が許可されているかどうかをチェックします。 プロセッサは、リスト上にある場合は接続を確立しようとし、そうでない場合は拒否しようとします。 これらのJAXPプロパティをカスタム・リゾルバ(「Java XMLリゾルバの使用」を参照してください)とともに使用して、外部接続を拒否してローカル・リソースで解決することで、外部接続のリスクを軽減します。
ノート: APIを介して(FSP)を保護処理する機能(factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true)
など)を明示的にオンにすると、すべての外部接続が無効になります。
外部アクセス制限のJAXPプロパティは、javax.xml.XMLConstants
で次のように定義されます:
javax.xml.XMLConstants.ACCESS_EXTERNAL_DTD
javax.xml.XMLConstants.ACCESS_EXTERNAL_SCHEMA
javax.xml.XMLConstants.ACCESS_EXTERNAL_STYLESHEET
属性 | 説明 |
---|---|
名前 |
http://javax.xml.XMLConstants/property/accessExternalDTD |
定義 | 外部DTDおよび外部エンティティ参照へのアクセスを指定されたプロトコルに制限します。 |
値 | 「外部アクセス制限のJAXPプロパティの値」を参照してください |
デフォルト値 | all。すべてのプロトコルへの接続が許可されます |
システム・プロパティ |
javax.xml.accessExternalDTD |
属性 | 説明 |
---|---|
名前 |
http://javax.xml.XMLConstants/property/accessExternalSchema |
定義 |
schemaLocation 属性、import 要素およびinclude 要素によって設定された外部参照用に指定されたプロトコルへのアクセスを制限します。 |
値 | 「外部アクセス制限のJAXPプロパティの値」を参照してください |
デフォルト値 | all。すべてのプロトコルへの接続が許可されます。 |
システム・プロパティ |
javax.xml.accessExternalSchema |
属性 | 説明 |
---|---|
名前 |
http://javax.xml.XMLConstants/property/accessExternalStylesheet |
定義 |
stylesheet 処理命令、document 関数、およびimport 要素とinclude 要素によって設定された外部参照用に指定されたプロトコルへのアクセスを制限します。 |
値 | 「外部アクセス制限のJAXPプロパティの値」を参照してください |
デフォルト値 | all。すべてのプロトコルへの接続が許可されます。 |
システム・プロパティ |
javax.xml.accessExternalStylesheet |
外部アクセス制限用のすべてのJAXPプロパティが同じ形式の値を持ちます。
値: カンマで区切られたプロトコルのリスト。 プロトコルは、URIのスキーム部分、またはJARプロトコルの場合は、jar
とコロンで区切られたスキーム部分です。 スキームは次のように定義されます。
scheme = alpha *( alpha | digit | "+" | "-" | "." )
ここで、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プロセッサ(DOM、SAX、スキーマ検証、XSLT、XPathなど)には、セキュア処理機能(FSP)が必要です。
FSPをオンにすると、デフォルトの処理制限(「処理制限用のJAXPプロパティ」を参照)が適用されます。 FSPをオフにしても制限は変更されません。
factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true)
などのAPIを介してFSPが"明示的に"をオンにすると、外部アクセス制限(「外部アクセス制限のJAXPプロパティ」を参照してください)が空の文字列に設定されます。これは、どのプロトコルにも権限が付与されないことを意味します。 DOM、SAXおよびスキーマ検証では、FSPはデフォルトでオンになっていますが、"明示的に"がオンのように扱われません。したがって、外部アクセス制限のデフォルト値はall
です。これは、すべてのプロトコルに権限が付与されることを意味します。
Javaセキュリティ・マネージャが存在する場合、FSPはオンになり、オフにはできません。
一般に、より小さいスコープに設定されたJAXPプロパティは、より大きいスコープのJAXPプロパティより優先されます。
jaxp.properties
ファイルおよびFSPよりも優先されます。jaxp.properties
ファイルで設定されているか、FSPによって設定されている処理制限および外部アクセス制限の値をオーバーライドします。jaxp.properties
ファイルで指定されたプロパティはJDK全体に影響し、デフォルトで設定されているかFSPで設定されている処理制限および外部アクセス制限の値をオーバーライドします。外部アクセス制限は、次のような状況で制限しようとする関連コンストラクトには影響しません。
リゾルバがあり、リゾルバによって返されたソースが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
JAXPプロパティは、SecurityManager
が存在するかどうかに関係なく、接続が試行される前に最初にチェックされます。 つまり、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
はテキストに表示できるノードの合計数に制限を設定し、システムのオーバーロードを防止します。
制限に対して設定する必要がある値を分析するために、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で処理制限サンプルを実行すると、次の表が出力されます。
プロパティ | 制限 | 合計サイズ | Size | エンティティ名 |
---|---|---|---|---|
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プロセッサおよびプロセスの最上位レイヤーに固有であり、つまり、プロセッサが接続を行う前にこれらの制限をチェックすることに注意してください。 したがって、外部接続リスクに対する、より直接的な追加の保護として機能します。
外部アクセス制限プロパティをカスタム・リゾルバおよびカタログ(「Java XMLリゾルバの使用」を参照してください)とともに使用して、外部接続を効果的に管理し、リスクを軽減できます。
信頼できるソースを含む信頼できる環境であっても、外部アクセス制限とリゾルバの両方を使用して外部ソースへの依存を最小限にすることをお薦めします。
アプリケーションのコードを変更したり、新しいアプリケーションを作成する場合は、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プロパティを他の手段で設定するかどうかに関係なく、アプリケーションの動作が同じようになります。
システム・プロパティは、アプリケーションのコードを変更できない場合に便利です。
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");
すべてのJDK呼出しに影響するJAXPプロパティを指定する場合は、<java-home>/lib/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プロパティの設定時にアプリケーションが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
を表します。
外部アクセス制限によって設定された制限が原因で外部リソースへのアクセスが拒否された場合、次の形式でエラーとともに例外がスローされます。
[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 (StAX)用のストリーミングAPI、JSR 173では、FSPがサポートされず、外部アクセス制限もサポートされません。 一方、JDKのStAX実装では処理制限がサポートされ、JAXPのコンテキストでのStAXでは外部アクセス制限がサポートされます。
JDKのStAX実装では、処理制限およびそれらに対応するシステム・プロパティがサポートされます。 ただし、FSPはサポートされていないため、FSPをオンまたはオフにすることによってStAXの処理制限をオンまたはオフにすることはできません。 処理制限は引き続き「処理制限用のJAXPプロパティ」に説明されているように動作します。
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
に設定することで、DTDを無効にしたアプリケーションには影響しません。
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に設定して拡張関数機能の再有効化を選択できます。 次の表で、このプロパティを定義します。
属性 | 説明 |
---|---|
名前 |
http://www.oracle.com/xml/jaxp/properties/enableExtensionFunctions |
定義 | XSLTおよびXPath拡張関数が許可されるかどうかを決定します。 |
値 | ブール Trueは拡張関数が許可されることを示します。それ以外の場合はFalseです。 |
デフォルト値 | true |
システム・プロパティ | jdk.xml.enableExtensionFunctions |
導入されたバージョン | 7u60 |
アプリケーションでDTDが必要ない場合は、DTD処理を無効化して、サービス拒否、XML外部エンティティ(XXE)、サーバー側リクエストの偽造(SSRF)など、多くの一般的な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処理を無効にするには、XMLInputFactory.setProperty
メソッドを使用してプロパティSupportDTD
を設定します:
XMLInputFactory xif = XMLInputFactory.newInstance(); xif.setProperty(XMLInputFactory.SUPPORT_DTD, Boolean.FALSE);
JDK XMLプロセッサにカスタム・リゾルバを登録して、外部リソースへの参照をインターセプトし、ローカル・リソースを使用して解決できます。 この機能によって、外部リソースの読み取りとアクセスの必要がなくなるため、潜在的なリスクのソースを除去するのに役立ちます。
Java XML APIでは、JDK XMLプロセッサに登録して外部リソースを解決できる様々なリゾルバがサポートされます。 これらのリゾルバには、SAXパーサーおよびDOMパーサーのエンティティ・リゾルバ、StAXパーサーのXMLリゾルバ、検証用のLSResourceResolver
および変換用のURIResolver
が含まれます。
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は、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
APIは、URIResolver
インタフェースを介して外部リソースのカスタム解決をサポートします:
package javax.xml.transform; public interface URIResolver { public Source resolve(String href, String base) throws TransformerException; }
URIResolver
の実装は、次のようにTransformer
に登録できます:
URIResolver resolver = ...; TransformerFactory tf = TransformerFactory.newInstance(); Transformer t = tf.newTransformer(new StreamSource( new StringReader("xsl source"))); t.setURIResolver(resolver);
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);
JDKでは、クラスパスにサードパーティ製のパーサーが存在する場合でも、常にシステムデフォルト・パーサーが使用されます。 JDKシステム・デフォルト・パーサーをオーバーライドするには、jdk.xml.overrideDefaultParser
プロパティをtrueに設定します。
属性 | 説明 |
---|---|
名前 | jdk.xml.overrideDefaultParser |
定義 | サードパーティのパーサー実装を使用して、JDKのTransformer 、Validator およびXPath 実装のシステム・デフォルト・パーサーをオーバーライドできます。 このプロパティは、JAXPファクトリ、システム・プロパティまたはjaxp.properties ファイルを通じて設定できます。 |
値 | ブール trueに設定すると、XML変換、XML検証またはXPath操作中にサードパーティ製パーサーの実装でシステムデフォルト実装をオーバーライドできます。 falseに設定すると、サードパーティ製パーサー実装の使用が無効になります。 値がStringとして指定されている場合、戻り値は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 | 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関連の機能とプロパティ |
JDK XML | Java XML APIのJDK実装 |
JDK XMLパーサー | XMLパーサーのJDK実装 |
JDK XMLプロパティ | JDK実装専用プロパティ |
FSP | FEATURE_SECURE_PROCESSING |
JavaおよびJDK XMLの機能およびプロパティは、javax.xml.XMLConstants
クラスで定義されます。 機能にはプレフィクスhttp://javax.xml.XMLConstants/feature
、プロパティhttp://javax.xml.XMLConstants/property
があります。 対応するSystemプロパティがある場合、プレフィクスはjavax.xml
です。
JDK XMLプロパティは、JDK実装専用のプロパティです。 プレフィクスは、JDKのバージョンによって異なります。 次の表に、この命名規則をまとめます。
有効範囲 | 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 |