Microsoft Edge 151では、XSLTを必要としないXML解析がRustベースのパーサーへ移行します。対象は主に、DOMParser、XMLHttpRequest.responseXML、SVG文書の解析です。狙いは、XML解析で発生し得るメモリ破損系の脆弱性を減らし、ブラウザの安全性を高めることにあります。(Microsoft Learn)
Web APIの使い方を変更するアップデートではないため、多くのWebサイトではコード修正は不要です。ただし、名前空間を多用するXML、解析結果を文字列として比較する処理、大容量XML、外部SVGを利用しているシステムでは、Edge 151で回帰テストを行っておくと安心です。
Edge 151のRust XMLパーサー移行で変わること
今回の変更は、新しいJavaScript APIを追加するものではありません。従来のXML解析処理を、メモリ安全性を重視したRust実装へ置き換える、ブラウザ内部の変更です。
| 項目 | Edge 151での扱い |
|---|---|
DOMParserによるXML解析 | Rustベースのパーサーを使用 |
XMLHttpRequest.responseXML | Rustベースのパーサーを使用 |
| SVG文書のXML解析 | Rustベースのパーサーを使用 |
| XSLTを必要とする処理 | 今回の移行対象外 |
| JavaScript APIの変更 | 原則なし |
| Webサイト側の必須対応 | なし |
| 管理ポリシーの設定 | 原則不要 |
| Microsoftの位置づけ | 情報提供 |
Chromium側でも、この変更は既存実装と機能的に同等であり、Webサイトから見える動作変更は想定されていません。試験段階で確認された互換性問題も修正され、残る互換性リスクは低いと評価されています。(Google グループ)
ただし、実装が変わる以上、すべての入力で解析結果が完全に同一になることを無条件に保証できるわけではありません。業務システムやXMLを中心に構築されたWebアプリでは、対象経路を特定して確認することが重要です。
Rust XMLパーサーの対象となる3つの経路
DOMParserでXML文字列を解析する処理
DOMParserは、文字列として受け取ったXMLをDOMへ変換するときに使われます。
const parser = new DOMParser();
const documentXml = parser.parseFromString(
'<items><item id="1">Sample</item></items>',
'application/xml'
);
const item = documentXml.querySelector('item');
console.log(item.textContent);
次のようなWebアプリでは、Edge 151の影響範囲に入ります。
- APIから取得したXML文字列を
DOMParserで解析している - ブラウザ内で設定ファイルやメタデータをXMLとして読み込んでいる
- SVG文字列を
image/svg+xmlとして解析している - XMLの解析後にXPathや名前空間APIを使っている
- 解析したDOMを
XMLSerializerで再び文字列へ戻している
fetch()自体にはresponseXMLに相当する機能がありません。ただし、fetch()で取得した文字列をDOMParserへ渡している場合は、DOMParserの解析経路が今回の対象になります。
const xmlText = await fetch('/data/items.xml').then(
response => response.text()
);
const xmlDocument = new DOMParser().parseFromString(
xmlText,
'application/xml'
);
XMLHttpRequest.responseXMLを使う処理
従来型のAjax処理や長期間運用されている業務システムでは、XMLHttpRequestのresponseXMLが使われていることがあります。
const xhr = new XMLHttpRequest();
xhr.open('GET', '/data/items.xml', true);
xhr.responseType = 'document';
xhr.onload = () => {
if (xhr.status < 200 || xhr.status >= 300) {
console.error(`HTTPエラー: ${xhr.status}`);
return;
}
const xmlDocument = xhr.responseXML;
if (!xmlDocument) {
console.error('XMLを解析できませんでした');
return;
}
const items = xmlDocument.getElementsByTagName('item');
console.log(items.length);
};
xhr.onerror = () => {
console.error('通信に失敗しました');
};
xhr.send();
Edge 151では、responseXMLとして返すDocumentを構築するXML解析にRustベースのパーサーが使われます。
この経路では、パーサー変更だけでなく、次の条件も結果に影響します。
- レスポンスの
Content-Type responseTypeの指定- XMLの文字コード
- XML宣言と実際のエンコーディングの一致
- CORSや認証の成否
- XML自体が整形式であるか
responseXMLがnullになった場合、すぐにRustパーサーの不具合と判断してはいけません。最初にネットワークタブでHTTPステータス、レスポンス本文、MIMEタイプを確認してください。
SVG文書のXML解析
SVGはXMLを基盤とする形式です。Edge 151では、SVG文書を解析する経路もRustベースのXMLパーサーへ移行します。Microsoftのリリースノートでは、SVG文書が明示的に対象として挙げられています。(Microsoft Learn)
特に確認したいのは、HTML内に直接記述した単純なインラインSVGよりも、次のような外部SVGです。
<img src="/assets/chart.svg" alt="グラフ">
<object
data="/assets/map.svg"
type="image/svg+xml">
</object>
このほか、次の利用方法も確認候補になります。
- CSSの
background-imageから読み込むSVG - SVGファイルをURLから直接開く処理
- 外部SVGのシンボルを参照する処理
- JavaScriptで取得したSVGをDOMとして加工する処理
- グラデーション、フィルター、マスク、クリッピングを含むSVG
- 名前空間を独自に定義したSVG
- 外部フォントや画像を参照するSVG
SVGが表示されるかだけでなく、寸法、色、フィルター、参照画像、クリック領域まで確認してください。複雑なSVGでは、スクリーンショットを使ったビジュアルリグレッションテストが有効です。
XSLTは今回の移行対象ではない
Edge 151の変更で重要なのは、非XSLTのXML解析だけが対象である点です。
次のような処理は、今回のRust XMLパーサー移行と同一視しないでください。
XSLTProcessorを使った変換- XSLスタイルシートを適用する処理
xml-stylesheet処理命令を利用するXML- XMLからHTMLや別形式のXMLを生成するXSLT処理
今回の変更は、「Edge 151でXSLTがRust化された」という意味ではありません。また、この情報だけを根拠にXSLTが削除されたと判断することもできません。
コード調査では、非XSLT経路とXSLT経路を分けて整理します。
rg -n \
"DOMParser|responseXML|XMLSerializer|XSLTProcessor|xml-stylesheet|\.svg" \
src public tests
XSLTProcessorやxml-stylesheetが見つかった箇所は、今回の対象外として別のテスト項目に分離すると、問題の切り分けがしやすくなります。
Rustへの移行で安全性が向上する理由
従来のChromium系ブラウザでは、XML解析の一部にC言語で実装されたライブラリが使われてきました。C言語では、メモリの確保や解放、ポインターの扱いに誤りがあると、解放済み領域へのアクセスやバッファー境界外へのアクセスなどにつながる可能性があります。
Rustは、所有権や型の仕組みによって、こうしたメモリ操作上の問題をコンパイル段階で防ぎやすい言語です。Edge 151の変更は、XML解析に由来するメモリ破損バグの一群を排除することを目的としています。(Google グループ)
ただし、Rustパーサーになったからといって、Webアプリ側のセキュリティ対策が不要になるわけではありません。
たとえば、XMLから取得した値を次のようにHTMLへ直接挿入するコードは、引き続き避ける必要があります。
resultElement.innerHTML = xmlDocument.querySelector('message').textContent;
単純なテキストを表示するだけなら、textContentを使います。
resultElement.textContent =
xmlDocument.querySelector('message')?.textContent ?? '';
ブラウザ内部のメモリ安全性向上と、Webアプリによる入力検証・出力処理は別の問題です。
優先的に回帰テストすべきWebサイト
すべてのWebサイトで大規模なテストを行う必要はありません。次の基準で優先順位を付けると効率的です。
| 優先度 | 該当するWebサイトやシステム |
|---|---|
| 高 | DOMParserやresponseXMLを主要機能で使っている |
| 高 | 名前空間、CDATA、XPath、XMLSerializerを多用している |
| 高 | 複雑な外部SVGを画面や帳票に利用している |
| 高 | 数MB以上のXMLをブラウザ上で解析している |
| 中 | 単純な外部SVGアイコンや図を利用している |
| 中 | XMLを補助的な設定ファイルとして読み込んでいる |
| 低 | JSONのみを扱い、XML解析を行っていない |
| 低 | PNGやWebPなど、XMLではない画像だけを使っている |
社内システムでは、古いAjaxライブラリや独自フレームワークの内部でresponseXMLが使われていることがあります。アプリケーションコードだけでなく、共通ライブラリや依存パッケージも検索してください。
DOMParserの回帰テスト手順
正常なXMLを解析する
名前空間、属性、CDATAを含むXMLをテストデータにすると、単純な要素だけを使うより広い範囲を確認できます。
const source = `<?xml version="1.0" encoding="UTF-8"?>
<catalog
xmlns="urn:example:catalog"
xmlns:meta="urn:example:meta">
<item id="A001" meta:status="active"><![CDATA[A&B]]></item>
</catalog>`;
const documentXml = new DOMParser().parseFromString(
source,
'application/xml'
);
const parseError =
documentXml.getElementsByTagName('parsererror')[0];
console.assert(!parseError, parseError?.textContent);
const item = documentXml.getElementsByTagNameNS(
'urn:example:catalog',
'item'
)[0];
console.assert(item?.textContent === 'A&B');
console.assert(item?.getAttribute('id') === 'A001');
console.assert(
item?.getAttributeNS('urn:example:meta', 'status') === 'active'
);
最低限、次の結果を確認します。
- パースエラーが発生しない
- ルート要素を取得できる
- 名前空間URIとローカル名が正しい
- 属性値を取得できる
- CDATAの内容が保持される
- 日本語や絵文字が文字化けしない
不正なXMLもテストする
正常なXMLだけでは、エラー処理の回帰を見つけられません。
const invalidXml = '<items><item></items>';
const documentXml = new DOMParser().parseFromString(
invalidXml,
'application/xml'
);
const hasParseError =
documentXml.getElementsByTagName('parsererror').length > 0;
console.assert(
hasParseError,
'不正なXMLがエラーとして検出されませんでした'
);
アプリ側がパースエラーを検出せず、そのままDOMを参照していると、ブラウザ更新後に画面が空になるだけで原因が分からないことがあります。エラー検出とログ出力を明示的に実装してください。
シリアライズは文字列の完全一致だけで判定しない
XMLをXMLSerializerで文字列化しているシステムでは、結果を元のXML文字列と完全一致させるテストに注意が必要です。
const serialized = new XMLSerializer().serializeToString(
documentXml
);
XMLでは、次のような違いがあっても意味が同じ場合があります。
- 名前空間宣言の位置
- 不要な名前空間宣言の追加
- 属性の表現方法
- 空要素の表記
- XML宣言の有無
- 改行やインデント
Chromiumの検証過程でも、名前空間を含む文書を再シリアライズした際の表現差が検討されました。文書の意味には影響しない差であるため、テストでは文字列だけでなく、名前空間URI、要素名、属性値、テキスト内容を比較する方法が適しています。(Google グループ)
XMLHttpRequest.responseXMLの確認項目
responseXMLを使うシステムでは、実際のサーバー応答を使って次の項目を確認します。
- 正常なXMLで
responseXMLが取得できる - 不正なXMLで期待どおりエラー処理される
- 日本語を含むXMLが文字化けしない
- 名前空間付き要素を取得できる
- 認証後のXMLレスポンスでも動作する
- キャッシュ利用時と未利用時の結果が同じ
- 大容量レスポンスでタイムアウトや画面停止が起きない
問題が発生した場合は、次の順序で切り分けます。
| 症状 | 最初に確認する項目 |
|---|---|
responseXMLがnull | HTTPステータス、MIMEタイプ、XML構文 |
| 文字化けする | HTTPヘッダー、XML宣言、実際の文字コード |
| 要素を取得できない | デフォルト名前空間、名前空間URI |
| 一部の属性だけ取れない | 接頭辞ではなく名前空間URIで取得しているか |
| Edgeだけ通信に失敗する | CORS、認証、証明書、CSP |
| 大容量XMLだけ遅い | 通信時間と解析時間を分けて計測 |
SVGは表示結果を画像で比較する
SVGの回帰テストでは、DOMの検査だけでなく実際の描画結果を比較します。
確認用ページには、少なくとも次のパターンを用意してください。
<h2>img要素</h2>
<img src="/fixtures/complex.svg" alt="検証用SVG">
<h2>object要素</h2>
<object
data="/fixtures/complex.svg"
type="image/svg+xml">
</object>
<h2>CSS背景</h2>
<div class="svg-background"></div>
.svg-background {
width: 320px;
height: 180px;
background-image: url("/fixtures/complex.svg");
background-repeat: no-repeat;
background-size: contain;
}
比較する内容は次のとおりです。
- SVG全体が表示されるか
viewBoxに基づく拡大縮小が正しいか- グラデーションやフィルターが欠落していないか
- マスクやクリッピングがずれていないか
- テキストやフォントが正しく表示されるか
- 外部画像や外部リソースが読み込まれるか
<use>で参照した図形が表示されるか- 直接URLを開いた場合も表示されるか
Edge 151だけでなく、更新前のEdgeでも同じページを表示し、同じ画面サイズと倍率でスクリーンショットを取得します。目視確認に加え、Playwrightなどを使った画像差分テストを組み込むと、わずかな描画差も検出できます。
大容量XMLでは処理時間も確認する
Rustへの移行目的は安全性向上であり、高速化ではありません。
Chromiumの事前検証では、XMLパーサー単体の処理時間に低下が確認された一方、主要な品質指標への影響は見られず、実際の処理時間は多くのケースで数十ミリ秒程度と報告されています。(Google グループ)
そのため、小さなXMLを扱う一般的なWebサイトで体感差が生じる可能性は低いものの、数MB以上のXMLを繰り返し解析するシステムでは実測が必要です。
const source = await fetch('/fixtures/large.xml').then(
response => response.text()
);
const start = performance.now();
const documentXml = new DOMParser().parseFromString(
source,
'application/xml'
);
const elapsed = performance.now() - start;
console.log(`XML解析時間: ${elapsed.toFixed(2)}ms`);
const hasError =
documentXml.getElementsByTagName('parsererror').length > 0;
console.assert(!hasError);
計測時は、次の条件をそろえます。
- 同じPCと同じXMLを使う
- 開発者ツールのCPUスロットリングを統一する
- 初回だけでなく複数回実行する
- 通信時間と解析時間を分ける
- Edge更新前後の中央値を比較する
- 実際の利用端末でも確認する
解析時間が業務に影響する場合は、XMLを小分けにする、サーバー側で必要部分だけ抽出する、JSONへ変換して配信するなど、ブラウザで解析するデータ量を減らす方法も検討します。
Edge 151移行時に起こりやすい誤解
RustになればXML入力を信頼してよい
Rust化されるのはブラウザ内部のパーサーです。XMLに含まれる値の正当性や、アプリ固有の権限、表示内容まで保証されるわけではありません。
入力値の検証、アクセス制御、出力時のエスケープは引き続き必要です。
すべてのXML処理がRustへ移行する
対象はXSLTを必要としない経路です。XSLT処理まで含めて一括で移行したわけではありません。
Edge 151を判定して処理を分岐すべき
Rust XMLパーサーはブラウザ内部の実装詳細です。Webページからパーサーの種類を判定してコードを分岐するのではなく、標準APIの結果を確認してください。
バージョン判定による回避コードを追加すると、将来のEdgeや他のChromium系ブラウザで保守負担が増えます。
XML文字列が完全一致しなければ不具合
名前空間宣言や空要素の表現が異なっても、DOMとして同じ意味を持つ場合があります。XMLの文字列だけでなく、要素、属性、名前空間、テキスト内容を比較してください。
SVGが表示されれば確認完了
静止状態で表示できても、拡大縮小、外部参照、フィルター、クリック操作などで問題が出る可能性があります。実際の利用場面を再現したテストが必要です。
管理者と開発者が取るべき対応
Edge 151のRust XMLパーサー移行は情報提供として扱われており、直ちに設定変更やコード修正を求めるものではありません。
一般利用者は特別な操作をする必要はありません。Webサイト管理者や企業のIT管理者は、次の順序で対応すると効率的です。
- ソースコードから
DOMParser、responseXML、外部SVGの利用箇所を探す XSLTProcessorなどのXSLT経路を分離する- 名前空間、不正XML、日本語、大容量XMLを含むテストデータを用意する
- Edge更新前後で同じ自動テストを実行する
- SVGはスクリーンショットでも比較する
- 問題がなければ通常どおりEdge 151を展開する
- 差異が出た場合は、通信、MIMEタイプ、文字コード、XML構文から順に切り分ける
Edge 151の変更は、Web開発者に新しいAPIへの書き換えを求めるものではなく、XML解析の内部実装をより安全なものへ置き換えるアップデートです。まずは、自社サイトやWebアプリがDOMParser、XMLHttpRequest.responseXML、外部SVGを使っているかを確認してください。該当する場合は、名前空間、エラー処理、シリアライズ、大容量XML、SVG描画を中心に回帰テストを行えば、実務上必要な確認を過不足なく進められます。

コメント