Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 14077] ファイルの概要

このコミットは、Go言語プロジェクトのmisc/chrome/gophertoolディレクトリにあるChrome拡張機能「gophertool」に関連する変更です。具体的には、以下の4つのファイルが変更されています。

  • misc/chrome/gophertool/background.html
  • misc/chrome/gophertool/background.js (新規作成)
  • misc/chrome/gophertool/popup.html
  • misc/chrome/gophertool/popup.js (新規作成)

これらの変更は、Chrome拡張機能のセキュリティ制限、特にHTMLファイル内でのインラインJavaScriptの禁止に対応するためのものです。

コミット

  • コミットハッシュ: 9e811683f1e4138820f0caaec20041c57c302f73
  • Author: Brad Fitzpatrick bradfitz@golang.org
  • Date: Sun Oct 7 17:56:10 2012 -0700

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/9e811683f1e4138820f0caaec20041c57c302f73

元コミット内容

gophertool: make work with latest Chrome extension security restrictions

No JavaScript in HTML anymore.

R=golang-dev, dsymonds
CC=golang-dev
https://golang.org/cl/6619066

変更の背景

このコミットの主な背景は、Google Chrome拡張機能におけるセキュリティモデルの強化です。特に、HTMLファイル内に直接JavaScriptコードを記述する「インラインスクリプト」がセキュリティ上のリスクと見なされ、新しいバージョンのChrome拡張機能では禁止されるようになりました。これは、クロスサイトスクリプティング(XSS)攻撃などの脆弱性を防ぐための重要な変更です。

gophertoolはChrome拡張機能であり、この新しいセキュリティ制限に準拠する必要がありました。以前のバージョンでは、background.htmlpopup.htmlといったHTMLファイル内に直接<script>タグでJavaScriptコードが埋め込まれていました。このコミットは、これらのインラインスクリプトを外部の.jsファイルに分離することで、最新のChrome拡張機能のセキュリティ要件を満たすことを目的としています。

前提知識の解説

Chrome拡張機能

Chrome拡張機能は、Google Chromeブラウザの機能を拡張するための小さなソフトウェアプログラムです。これらはHTML、CSS、JavaScriptといった標準的なウェブ技術を使用して開発され、ブラウザのUIを変更したり、ウェブページのコンテンツを操作したり、新しい機能を追加したりすることができます。拡張機能は、特定の権限(例: タブへのアクセス、特定のURLへのアクセス)を要求し、ユーザーがそれらの権限を許可することで動作します。

Content Security Policy (CSP)

Content Security Policy (CSP)は、ウェブサイトやウェブアプリケーションが、読み込みを許可するリソースの種類とソースを宣言するためのセキュリティメカニズムです。CSPは、XSS攻撃などの特定の種類の攻撃を軽減するのに役立ちます。Chrome拡張機能では、manifest.jsonファイルでCSPを定義し、拡張機能が読み込むことができるスクリプト、スタイルシート、画像などのリソースのソースを厳しく制限します。

CSPの重要な側面の一つは、インラインスクリプトの禁止です。これは、HTMLファイル内に直接記述された<script>タグや、onclickなどのインラインイベントハンドラを指します。CSPが有効な場合、これらのインラインスクリプトは実行されません。これは、攻撃者がウェブページに悪意のあるスクリプトを注入しようとした場合でも、そのスクリプトが実行されるのを防ぐためです。

インラインスクリプトのセキュリティリスク

インラインスクリプトは、XSS攻撃の主要なベクトルの一つです。XSS攻撃では、攻撃者が悪意のあるスクリプトをウェブページに注入し、そのスクリプトがユーザーのブラウザで実行されます。これにより、セッションハイジャック、データの盗難、マルウェアの配布など、さまざまな悪意のある活動が可能になります。

インラインスクリプトを禁止することで、CSPはこれらの攻撃のリスクを大幅に低減します。なぜなら、攻撃者がページにスクリプトを注入できたとしても、そのスクリプトがインラインである限り、CSPによって実行がブロックされるためです。これにより、開発者はすべてのJavaScriptコードを外部ファイルに分離し、そのファイルのハッシュやソースをCSPで明示的に許可する必要があるため、より安全なコーディングプラクティスが強制されます。

技術的詳細

このコミットは、Chrome拡張機能のセキュリティ制限、特にインラインJavaScriptの禁止に対応するために、既存のJavaScriptコードをHTMLファイルから分離し、専用の外部JavaScriptファイルに移動するという一般的なパターンを適用しています。

具体的には、以下の変更が行われました。

  1. background.htmlからのJavaScriptの分離:

    • 以前はbackground.html内に直接記述されていたchrome.omnibox.onInputEntered.addListenerのコードブロックが削除されました。
    • このコードは新しく作成されたbackground.jsファイルに移動されました。
    • background.htmlは、background.jsを外部スクリプトとして読み込むように変更されました(<script src="background.js"></script>)。
  2. popup.htmlからのJavaScriptの分離:

    • 以前はpopup.html内に直接記述されていたfocusinput(), navigate(), openURL()などの関数を含むJavaScriptコードブロックが削除されました。
    • これらの関数と関連するロジックは新しく作成されたpopup.jsファイルに移動されました。
    • popup.htmlは、popup.jsを外部スクリプトとして読み込むように変更されました(<script src="popup.js"></script>)。
    • また、popup.html内のインラインイベントハンドラ(例: onload="focusinput()"onsubmit="return navigate();"onclick="openURL(...)")も削除され、JavaScript側でイベントリスナーを登録する形式に変更されました。これは、インラインイベントハンドラもCSPの制限の対象となるためです。

これらの変更により、gophertool拡張機能は、HTMLファイル内にインラインスクリプトを含まない状態となり、Chromeの最新のセキュリティポリシーに準拠するようになりました。これにより、拡張機能のセキュリティが向上し、将来のChromeのアップデートによる互換性の問題も回避されます。

コアとなるコードの変更箇所

misc/chrome/gophertool/background.html

--- a/misc/chrome/gophertool/background.html
+++ b/misc/chrome/gophertool/background.html
@@ -6,19 +6,7 @@
 -->
 <head>
 <script src="gopher.js"></script>
-<script>
-    
-chrome.omnibox.onInputEntered.addListener(function(t) {
-  var url = urlForInput(t);
-  if (url) {
-    chrome.tabs.getSelected(null, function(tab) {
-      if (!tab) return;
-      chrome.tabs.update(tab.id, { "url": url, "selected": true });
-    });
-  }
-});
-
-</script>
+<script src="background.js"></script>
 </head>
 </html>

misc/chrome/gophertool/background.js (新規作成)

--- /dev/null
+++ b/misc/chrome/gophertool/background.js
@@ -0,0 +1,9 @@
+chrome.omnibox.onInputEntered.addListener(function(t) {
+  var url = urlForInput(t);
+  if (url) {
+    chrome.tabs.getSelected(null, function(tab) {
+      if (!tab) return;
+      chrome.tabs.update(tab.id, { "url": url, "selected": true });
+    });
+  }
+});

misc/chrome/gophertool/popup.html

--- a/misc/chrome/gophertool/popup.html
+++ b/misc/chrome/gophertool/popup.html
@@ -6,49 +6,14 @@
 -->
 <head>
 <script src="gopher.js"></script>
-<script>
-    
-function focusinput() {
-  document.getElementById("inputbox").focus();
-}
-
-function navigate() {
-  var box = document.getElementById("inputbox");
-  box.focus();
-
-  var t = box.value;
-  if (t == "") {
-    return false;
-  }
-
-  var success = function(url) {
-    console.log("matched " + t + " to: " + url)
-    box.value = "";
-    openURL(url);
-    return false;  // cancel form submission
-  };
-
-  var url = urlForInput(t);
-  if (url) {
-    return success(url);
-  }
-
-  console.log("no match for text: " + t)
-  return false;
-}
-
-function openURL(url) {
-  chrome.tabs.create({ "url": url })
-}
-
-</script>
+<script src="popup.js"></script>
 </head>
-<body onload="focusinput()" style='margin: 0.5em; font-family: sans;'>
+<body style='margin: 0.5em; font-family: sans;'>
 <small><a href="#" onclick="openURL('http://code.google.com/p/go/issues/list')">issue</a>,
 <a href="#" onclick="openURL('http://codereview.appspot.com/')">codereview</a>,
 <a href="#" onclick="openURL('http://code.google.com/p/go/source/list')">commit</a>, or
 <a href="#" onclick="openURL('http://golang.org/pkg/')">pkg</a> id/name:</small>
-<form style='margin: 0' onsubmit="return navigate();"><nobr><input id="inputbox" size=10 tabindex=1 /><input type="submit" value="go" /></nobr></form>
-<small>Also: <a href="#" onclick="openURL('http://build.golang.org/')">buildbots</small>
+<form style='margin: 0' id='navform'><nobr><input id="inputbox" size=10 tabindex=1 /><input type="submit" value="go" /></nobr></form>
+<small>Also: <a href="#" id='buildbotslink'>buildbots</small>
 </body>
 </html>

misc/chrome/gophertool/popup.js (新規作成)

--- /dev/null
+++ b/misc/chrome/gophertool/popup.js
@@ -0,0 +1,38 @@
+function openURL(url) {
+  chrome.tabs.create({ "url": url })
+}
+
+window.addEventListener("load", function () {
+  console.log("hacking gopher pop-up loaded.");
+  document.getElementById("inputbox").focus();
+});
+
+window.addEventListener("submit", function () {
+  console.log("submitting form");
+  var box = document.getElementById("inputbox");
+  box.focus();
+
+  var t = box.value;
+  if (t == "") {
+    return false;
+  }
+
+  var success = function(url) {
+    console.log("matched " + t + " to: " + url)
+    box.value = "";
+    openURL(url);
+    return false;  // cancel form submission
+  };
+
+  var url = urlForInput(t);
+  if (url) {
+    return success(url);
+  }
+
+  console.log("no match for text: " + t)
+  return false;
+});
+
+window.addEventListener("click", function () {
+  openURL("http://build.golang.org/");
+});

コアとなるコードの解説

background.js

このファイルは、Chrome拡張機能のバックグラウンドページで実行されるスクリプトです。主な役割は、Chromeのオムニボックス(アドレスバー)に入力されたテキストを処理し、それに基づいて新しいタブを開くことです。

  • chrome.omnibox.onInputEntered.addListener(function(t) { ... });
    • これは、ユーザーがChromeのオムニボックスに何かを入力し、Enterキーを押したときに発生するイベントをリッスンするものです。
    • tはユーザーが入力したテキストです。
    • urlForInput(t): この関数(gopher.jsで定義されていると推測される)は、入力されたテキストに基づいて適切なURLを生成します。例えば、Goのイシュー番号やコミットハッシュからGitHubのURLを生成するなどの機能が考えられます。
    • chrome.tabs.getSelected(null, function(tab) { ... });: 現在選択されているタブを取得します。
    • chrome.tabs.update(tab.id, { "url": url, "selected": true });: 取得したURLで現在のタブを更新し、そのタブを選択状態にします。これにより、ユーザーはオムニボックスから直接Go関連のページに素早くアクセスできるようになります。

popup.js

このファイルは、Chrome拡張機能のポップアップウィンドウ(ブラウザのツールバーアイコンをクリックしたときに表示される小さなウィンドウ)で実行されるスクリプトです。ユーザーがポップアップで入力した内容を処理し、関連するGoのページにナビゲートする機能を提供します。

  • function openURL(url) { chrome.tabs.create({ "url": url }) }

    • 指定されたURLで新しいタブを開くシンプルなヘルパー関数です。
  • window.addEventListener("load", function () { ... });

    • ポップアップウィンドウが完全に読み込まれたときに実行されます。
    • document.getElementById("inputbox").focus();: ポップアップが開いたときに、入力ボックスに自動的にフォーカスを合わせることで、ユーザーがすぐにテキストを入力できるようにします。
  • window.addEventListener("submit", function () { ... });

    • ポップアップ内のフォームが送信されたときに実行されます。
    • var box = document.getElementById("inputbox");: 入力ボックスのDOM要素を取得します。
    • var t = box.value;: 入力ボックスの現在の値(ユーザーが入力したテキスト)を取得します。
    • 入力が空の場合は処理を中断します。
    • var success = function(url) { ... };: URLが正常に生成された場合のコールバック関数です。入力ボックスをクリアし、openURLを呼び出して新しいタブを開きます。
    • var url = urlForInput(t);: gopher.jsで定義されているurlForInput関数を使用して、入力テキストからURLを生成します。
    • URLが生成された場合、successコールバックを実行します。
    • URLが生成されなかった場合、コンソールにメッセージを出力します。
    • return false;: フォームのデフォルトの送信動作をキャンセルします。
  • window.addEventListener("click", function () { ... });

    • ポップアップ内のどこかがクリックされたときに実行されます。
    • openURL("http://build.golang.org/");: このイベントリスナーは、popup.htmlから削除されたbuildbotsリンクのインラインonclickハンドラを置き換えるものです。これにより、ユーザーがポップアップ内の特定のリンクをクリックすると、Goのビルドボットページが新しいタブで開かれます。

これらの変更により、JavaScriptコードはHTMLから完全に分離され、Chrome拡張機能のセキュリティ要件に準拠しつつ、以前と同じ機能を提供しています。

関連リンク

参考にした情報源リンク