[インデックス 11118] ファイルの概要
このコミットは、Go言語のhtml/template
パッケージにおけるエスケープ処理のバグ修正と、それに伴い無効化されていたテストケースの再有効化に関するものです。特に、CSSの16進エスケープシーケンスがテンプレートパーサーによって誤って解釈されていた問題と、ヌル文字(NUL)の適切なエスケープ処理に焦点を当てています。
コミット
html/template: reenable testcases and fix mis-escaped sequences.
Tighter octal parsing broke some tests and were disabled in
https://golang.org/cl/5530051
Those tests were broken. The CSS decoder was supposed to see CSS
hex escape sequences of the form '\' <hex>+, but those escape
sequences were instead being consumed by the template parser.
This change properly escapes those escape sequences, and uses
proper escaping for NULs.
R=golang-dev, rsc, nigeltao
CC=golang-dev
https://golang.org/cl/5529073
GitHub上でのコミットページへのリンク
https://github.com/golang/go/commit/b1d6fa517cd99cbbad1523dddc6182da5a701122
元コミット内容
commit b1d6fa517cd99cbbad1523dddc6182da5a701122
Author: Mike Samuel <mikesamuel@gmail.com>
Date: Wed Jan 11 18:47:03 2012 -0500
html/template: reenable testcases and fix mis-escaped sequences.
Tighter octal parsing broke some tests and were disabled in
https://golang.org/cl/5530051
Those tests were broken. The CSS decoder was supposed to see CSS
hex escape sequences of the form '\' <hex>+, but those escape
sequences were instead being consumed by the template parser.
This change properly escapes those escape sequences, and uses
proper escaping for NULs.
R=golang-dev, rsc, nigeltao
CC=golang-dev
https://golang.org/cl/5529073
変更の背景
この変更の背景には、Go言語のhtml/template
パッケージにおけるセキュリティと堅牢性の向上が挙げられます。以前のコミット(https://golang.org/cl/5530051
で言及されている「Tighter octal parsing」)によって、より厳密な8進数パースが導入されました。この変更自体はセキュリティ強化を目的としたものと考えられますが、その副作用として、既存のテストケースが失敗するようになりました。
具体的には、CSSの16進エスケープシーケンス(例: \78
)が、CSSデコーダではなくテンプレートパーサーによって誤って解釈されてしまう問題が発生していました。これにより、本来CSSとして処理されるべき文字列が、テンプレートの構文として扱われ、意図しない挙動や、最悪の場合にはクロスサイトスクリプティング(XSS)などのセキュリティ脆弱性につながる可能性がありました。
この問題に対処するため、一時的に関連するテストケースが無効化されていましたが、本コミットではその根本原因を修正し、テストケースを再有効化することで、html/template
パッケージの正確性と安全性を回復させることを目的としています。また、ヌル文字(\0
)の適切なエスケープ処理も同時に修正されています。
前提知識の解説
Go言語のhtml/template
パッケージ
html/template
パッケージは、Go言語の標準ライブラリの一部であり、HTML出力の自動エスケープ機能を提供します。これは、Webアプリケーションにおけるクロスサイトスクリプティング(XSS)攻撃を防ぐために非常に重要です。このパッケージは、テンプレート内のデータがHTML、CSS、JavaScriptなどの異なるコンテキストで使用される際に、それぞれのコンテキストに応じた適切なエスケープ処理を自動的に適用します。
エスケープ処理
エスケープ処理とは、特定の文字が特別な意味を持つコンテキストにおいて、その文字をリテラルとして扱わせるために、別の表現に変換することです。例えば、HTMLでは<
や>
はタグの開始・終了を示すため、これらをテキストとして表示したい場合は<
や>
といったHTMLエンティティにエスケープする必要があります。
CSSエスケープシーケンス
CSSでは、特定の文字(例: スペース、予約語の一部、非ASCII文字など)をプロパティ値やセレクタ名で使用するために、エスケープシーケンスが定義されています。最も一般的なのはバックスラッシュ(\
)に続く1つまたは複数の16進数で文字を表す形式です(例: \78
はx
を表す)。これは、CSSパーサーがこれらのシーケンスを単一の文字として解釈することを意図しています。
ヌル文字(NUL)のエスケープ
ヌル文字(ASCIIコード0、\0
)は、文字列の終端を示すためによく使用される制御文字です。しかし、Webコンテキスト、特にJavaScriptやCSSの文脈では、ヌル文字が文字列の途中で現れると、その後の文字が無視されたり、予期しないパース挙動を引き起こしたりする可能性があります。そのため、セキュリティ上の理由から、ヌル文字も適切にエスケープされる必要があります。
テンプレートパーサーとCSSデコーダの相互作用
Webアプリケーションでは、HTMLテンプレート内にCSSスタイルが埋め込まれることがよくあります。この際、テンプレートエンジンはまずテンプレート構文を解析し、その後にCSSコンテキスト内の文字列をCSSデコーダが解析するという多段階の処理が行われます。このコミットの問題は、この多段階処理において、CSSデコーダが処理する前にテンプレートパーサーがCSSエスケープシーケンスを誤って「消費」してしまい、CSSデコーダに正しく渡らなかったことに起因します。
技術的詳細
このコミットの核心は、html/template
パッケージがCSSコンテキスト内で文字列をエスケープする際のロジックの改善にあります。
問題は、CSSの16進エスケープシーケンス(例: \78
)が、テンプレートパーサーによって通常の文字列の一部としてではなく、何らかのテンプレート構文の一部として誤って解釈されてしまうことにありました。これは、テンプレートパーサーが8進数パースをより厳密にした結果、CSSエスケープシーケンスのバックスラッシュとそれに続く数字を、テンプレート自身の内部的なエスケープメカニズムと混同してしまった可能性が考えられます。
修正は、テンプレートパーサーがCSSコンテキスト内の文字列を処理する際に、CSSの仕様に則ったエスケープシーケンスを正しく認識し、それらをそのままCSSデコーダに渡すように変更されたことを示唆しています。これにより、CSSデコーダは期待通りにこれらのエスケープシーケンスを解釈し、正しいCSS値を生成できるようになります。
また、ヌル文字(\0
)の適切なエスケープも重要な修正点です。ヌル文字は、多くのプログラミング言語やシステムで文字列の終端を示すために使われますが、WebブラウザのCSSやJavaScriptパーサーでは、ヌル文字が予期しない挙動を引き起こすことがあります。例えば、ヌル文字以降の文字列が切り捨てられたり、セキュリティバイパスに利用されたりする可能性があります。この修正により、html/template
はヌル文字を安全な形式(例: \000
や\x00
など、CSSやJavaScriptで安全に扱える形式)に変換することで、これらの潜在的な問題を回避します。
この変更は、html/template
パッケージが提供する自動エスケープ機能の堅牢性を高め、開発者が意図しないセキュリティ脆弱性を導入するリスクを低減します。特に、ユーザー入力がCSSプロパティ値として使用されるようなシナリオにおいて、XSS攻撃に対する防御を強化します。
コアとなるコードの変更箇所
変更はsrc/pkg/html/template/escape_test.go
ファイルに対して行われています。
--- a/src/pkg/html/template/escape_test.go
+++ b/src/pkg/html/template/escape_test.go
@@ -300,23 +300,21 @@ func TestEscape(t *testing.T) {
`<p style="color: {{\"#8ff\"}}; background: {{\"#000\"}}\">`,\
`<p style="color: #8ff; background: #000\">`,\
},\
-\t\t// This test is broken by the fix to issue 2658.\
-\t\t// {\
-\t\t// \t\"styleObfuscatedExpressionBlocked\",\
-\t\t// \t`<p style=\"width: {{\" e\\78preS\\0Sio/**/n(alert(1337))\"}}\">`,\
-\t\t// \t`<p style=\"width: ZgotmplZ\">`,\
-\t\t// },\
+\t\t{\
+\t\t\t\"styleObfuscatedExpressionBlocked\",\
+\t\t\t`<p style=\"width: {{\" e\\\\78preS\\x00Sio/**/n(alert(1337))\"}}\">`,\
+\t\t\t`<p style=\"width: ZgotmplZ\">`,\
+\t\t},\
\t\t{\
\t\t\t\"styleMozBindingBlocked\",\
\t\t\t`<p style=\"{{\"-moz-binding(alert(1337))\"}}: ...\">`,\
\t\t\t`<p style=\"ZgotmplZ: ...\">`,\
\t\t},\
-\t\t// This test is broken by the fix to issue 2658.\
-\t\t// {\
-\t\t// \t\"styleObfuscatedMozBindingBlocked\",\
-\t\t// \t`<p style=\"{{\" -mo\\7a-B\\0I/**/nding(alert(1337))\"}}: ...\">`,\
-\t\t// \t`<p style=\"ZgotmplZ: ...\">`,\
-\t\t// },\
+\t\t{\
+\t\t\t\"styleObfuscatedMozBindingBlocked\",\
+\t\t\t`<p style=\"{{\" -mo\\\\7a-B\\x00I/**/nding(alert(1337))\"}}: ...\"}}>`,\
+\t\t\t`<p style=\"ZgotmplZ: ...\">`,\
+\t\t},\
\t\t{\
\t\t\t\"styleFontNameString\",\
\t\t\t`<p style=\'font-family: \"{{\"Times New Roman\"}}\"\'>`,\
コアとなるコードの解説
このコミットにおけるコードの変更は、主にescape_test.go
ファイル内のコメントアウトされていたテストケースを再有効化し、その入力文字列を修正することにあります。
具体的には、以下の2つのテストケースが対象です。
-
"styleObfuscatedExpressionBlocked"
:- 元のコメントアウトされたコードでは、入力文字列に
e\78preS\0Sio/**/n(alert(1337))
というCSSの難読化された表現が含まれていました。ここで\78
はx
を、\0
はヌル文字を表します。 - 修正後、入力文字列は
e\\\\78preS\\x00Sio/**/n(alert(1337))
に変更されています。e\\78
:\
が二重になっているのは、Goの文字列リテラル内で\
をエスケープするためです。実際のCSSコンテキストでは\78
として解釈されます。\\x00
: ヌル文字\0
が\x00
という16進エスケープシーケンスに置き換えられています。これは、CSSやJavaScriptにおいてヌル文字を安全に表現するための一般的な方法です。
- このテストは、難読化されたCSS式(
expression(alert(1337))
のようなもの)が、html/template
によって安全なZgotmplZ
に置き換えられることを検証しています。これは、CSSインジェクションによるXSS攻撃を防ぐための重要なセキュリティ機能です。
- 元のコメントアウトされたコードでは、入力文字列に
-
"styleObfuscatedMozBindingBlocked"
:- 同様に、元のコメントアウトされたコードでは、入力文字列に
-mo\7a-B\0I/**/nding(alert(1337))
という難読化されたCSSの-moz-binding
プロパティの表現が含まれていました。 - 修正後、入力文字列は
-mo\\\\7a-B\\x00I/**/nding(alert(1337))
に変更されています。- ここでも
\
が二重になり、\0
が\x00
に置き換えられています。
- ここでも
- このテストは、
-moz-binding
プロパティ(FirefoxでXBLバインディングを適用するために使われた非標準のプロパティで、セキュリティリスクがある)が、html/template
によってブロックされ、ZgotmplZ
に置き換えられることを検証しています。
- 同様に、元のコメントアウトされたコードでは、入力文字列に
これらの変更は、html/template
パッケージの内部的なエスケープロジックが、CSSの16進エスケープシーケンスとヌル文字を正しく処理できるようになったことを示しています。これにより、以前は誤って解釈され、テストが失敗していたケースが、正しくセキュリティフィルタリングされるようになりました。テストケースの再有効化は、この修正が期待通りに機能していることを確認するためのものです。
関連リンク
- Go言語の
html/template
パッケージに関する公式ドキュメント: https://pkg.go.dev/html/template - CSSエスケープシーケンスに関するMDN Web Docs: https://developer.mozilla.org/ja/docs/Web/CSS/Escaping_special_characters
- クロスサイトスクリプティング (XSS) に関するOWASPの解説: https://owasp.org/www-community/attacks/xss/
参考にした情報源リンク
- コミットメッセージに記載されているGo CL (Change List) へのリンク:
https://golang.org/cl/5530051
(Web検索ツールでは直接内容にアクセスできませんでした)https://golang.org/cl/5529073
(Web検索ツールでは直接内容にアクセスできませんでした)
- Go言語の
html/template
パッケージのソースコード(GitHub): https://github.com/golang/go/tree/master/src/html/template - 一般的なWebセキュリティとエスケープ処理に関する知識。
- CSSの仕様に関する一般的な知識。
- Go言語の文字列リテラルにおけるエスケープルールに関する知識。