XMLファイルをPHPで処理する場合、 XML_SET_EXTERNAL_ENTITY_REF_HANDLERおよびLIBXML_DISABLE_ENTITY_LOADERは、それぞれ外部エンティティを処理し、外部エンティティのロードを無効にするために使用される2つの一般的に使用される関数です。ただし、両方を使用すると、特に外部DTD(ドキュメントタイプの定義)とエンティティを含むXMLを扱う場合、いくつかの互換性の問題を引き起こす可能性があります。この記事では、これらの問題の根本原因を調査し、解決策を提供します。
xml_set_external_entity_ref_handlerは、XMLドキュメント内の外部エンティティへの参照を処理するカスタムコールバック関数を指定できるPHP関数です。外部エンティティは、DTDファイル、その他のXMLファイル、テキストファイルなどのXMLドキュメントに外部リソースを導入するために多くの場合使用されます。
外部エンティティリファレンスでXMLドキュメントを解析するとき、 XML_SET_EXTERNAL_ENTITY_REF_HANDLERが定義するコールバック関数を呼び出し、エンティティの解析前に処理ロジックをカスタマイズできます。
libxml_disable_entity_loaderは、XMLパーサーを無効にして外部エンティティをロードする別のPHP関数です。この機能は通常、XML外部エンティティインジェクション攻撃を防ぐために使用されます(XXE攻撃)。外部エンティティのロードを無効にすることにより、XMLパーサーが誤って外部リソースから機密情報をロードしないようにすることができます。
これら2つの関数の機能は無関係であるように見えますが、それらは矛盾する可能性があります。 XML_SET_EXTERNAL_ENTITY_REF_HANDLERは、外部エンティティのロードを処理できることを期待していますが、 LIBXML_DISABLE_ENTITY_LOADERは外部エンティティのロードを無効にします。エンティティの読み込みが無効になっている場合、XMLパーサーが外部エンティティをロードしようとしないため、 XML_SET_EXTERNAL_ENTITY_REF_HANDLERのコールバック関数をトリガーできません。
これは、2つの間の互換性の問題につながります。 XML_SET_EXTERNAL_ENTITY_REF_HANDLERを使用して、エンティティのロードを無効にした後に外部エンティティ参照を処理する場合は、特別な措置を講じる必要があります。
xml_set_external_entity_ref_handlerがlibxml_disable_entity_loaderと互換性があることを確認するには、次の方法を取得できます。
最も一般的な慣行は、XXE攻撃を防ぐために外部エンティティのロードを無効にすることですが、 XML_SET_EXTERNAL_ENTITY_REF_HANDLERを使用して特定の外部エンティティ参照を処理することです。これを達成するには、次のコードを使用できます。
<span><span><span class="hljs-comment">// 外部エンティティの読み込みを無効にします</span></span><span>
</span><span><span class="hljs-title function_ invoke__">libxml_disable_entity_loader</span></span><span>(</span><span><span class="hljs-literal">true</span></span><span>);
</span><span><span class="hljs-comment">// 外部エンティティ参照処理機能のセットアップ</span></span><span>
</span><span><span class="hljs-title function_ invoke__">xml_set_external_entity_ref_handler</span></span><span>(function (</span><span><span class="hljs-variable">$entity</span></span><span>, </span><span><span class="hljs-variable">$system</span></span><span>, </span><span><span class="hljs-variable">$public</span></span><span>) {
</span><span><span class="hljs-comment">// 外部エンティティ参照を処理します</span></span><span>
</span><span><span class="hljs-comment">// たとえば、ローカルファイルまたはデータベースからエンティティをロードします</span></span><span>
</span><span><span class="hljs-keyword">return</span></span><span> </span><span><span class="hljs-string">'/path/to/your/local/entity'</span></span><span>;
});
</span><span><span class="hljs-comment">// 分析 XML</span></span><span>
</span><span><span class="hljs-variable">$xml</span></span><span> = </span><span><span class="hljs-title function_ invoke__">simplexml_load_file</span></span><span>(</span><span><span class="hljs-string">'yourfile.xml'</span></span><span>);
</span></span>
このようにして、 libxml_disable_entity_loaderはすべての外部エンティティのロードを無効にしますが、 xml_set_external_entity_ref_handlerを使用して、特定の外部エンティティに遭遇したときに処理をカスタマイズできます。
特定の状況で外部エンティティをロードできるようにする必要がある場合、特定の処理段階でエンティティの読み込みを一時的に有効にすることができます。 XMLを解析する前後にエンティティの読み込みを明示的に有効または無効にすることができます。
<span><span><span class="hljs-comment">// 外部エンティティの読み込みを無効にします</span></span><span>
</span><span><span class="hljs-title function_ invoke__">libxml_disable_entity_loader</span></span><span>(</span><span><span class="hljs-literal">true</span></span><span>);
</span><span><span class="hljs-comment">// 分析 XML</span></span><span>
</span><span><span class="hljs-variable">$xml</span></span><span> = </span><span><span class="hljs-title function_ invoke__">simplexml_load_file</span></span><span>(</span><span><span class="hljs-string">'yourfile.xml'</span></span><span>);
</span><span><span class="hljs-comment">// 外部エンティティが特定の瞬間にロードできるようにします</span></span><span>
</span><span><span class="hljs-title function_ invoke__">libxml_disable_entity_loader</span></span><span>(</span><span><span class="hljs-literal">false</span></span><span>);
</span><span><span class="hljs-comment">// 他の操作を続けます</span></span><span>
</span></span>
このアプローチにより、外部エンティティがロードされる時期をより詳細に制御でき、セキュリティの問題を避けながら柔軟なXML解析を許可します。
外部エンティティのロードを無効にしたくないが、セキュリティの問題を回避したい場合は、 XML_SET_EXTERNAL_ENTITY_REF_HANDLER CallBack関数内にセキュリティチェックを実装できます。たとえば、外部エンティティのURIが信頼できるかどうかを確認するか、ローカルファイルをロードできるかどうかを確認できます。
<span><span><span class="hljs-comment">// 外部エンティティ参照処理機能のセットアップ</span></span><span>
</span><span><span class="hljs-title function_ invoke__">xml_set_external_entity_ref_handler</span></span><span>(function (</span><span><span class="hljs-variable">$entity</span></span><span>, </span><span><span class="hljs-variable">$system</span></span><span>, </span><span><span class="hljs-variable">$public</span></span><span>) {
</span><span><span class="hljs-comment">// 安全検査を実施します,信頼されていないエンティティがロードされていないことを確認してください</span></span><span>
</span><span><span class="hljs-keyword">if</span></span><span> (</span><span><span class="hljs-title function_ invoke__">strpos</span></span><span>(</span><span><span class="hljs-variable">$system</span></span><span>, </span><span><span class="hljs-string">'trusted-path'</span></span><span>) === </span><span><span class="hljs-literal">false</span></span><span>) {
</span><span><span class="hljs-keyword">return</span></span><span> </span><span><span class="hljs-string">''</span></span><span>; </span><span><span class="hljs-comment">// 空の文字列を返して、エンティティがロードされていないことを示します</span></span><span>
}
</span><span><span class="hljs-comment">// 信頼できる外部エンティティを処理します</span></span><span>
</span><span><span class="hljs-keyword">return</span></span><span> </span><span><span class="hljs-string">'/path/to/your/trusted/entity'</span></span><span>;
});
</span><span><span class="hljs-comment">// 分析 XML</span></span><span>
</span><span><span class="hljs-variable">$xml</span></span><span> = </span><span><span class="hljs-title function_ invoke__">simplexml_load_file</span></span><span>(</span><span><span class="hljs-string">'yourfile.xml'</span></span><span>);
</span></span>
このアプローチにより、外部エンティティがロードできるようにしながら、どのエンティティをロードできるかを制御でき、潜在的なセキュリティリスクを回避できます。
PHPでは、2つの関数xml_set_external_entity_ref_handlerとlibxml_disable_entity_loaderには異なる目的がありますが、それらの間に矛盾がある場合があります。合理的な構成とコードの調整により、これら2つの機能が互換性があることを確認し、外部エンティティ参照処理のニーズを満たし、外部エンティティのロードによってもたらされるセキュリティリスクを回避できます。適切なソリューションを選択することは、特定のニーズとセキュリティ要件に依存します。