現在、当サイト「mozilla.org 日本語版」の和訳文書は更新されておらず、mozilla.org の原文 よりも内容が古くなっている可能性があります。ご不便をお掛けしますが、最新の情報は原文をご確認ください。



設定可能なセキュリティポリシー


Jesse Ruderman


設定可能なセキュリティポリシー とは何なのか?

Mozilla の設定可能なセキュリティポリシーでは、ユーザがブラウザに関してセキュリティポリシーを設定でき、異なるインターネットサイトに対して異なるセキュリティポリシーを持つことができます。この設定可能なセキュリティポリシーという考え方は、様々な考え方から生まれました。Bell 研究所の研究員である Vinod Anupam と Alain Mayer は、資料を作成し Mozilla にコードを貢献しました。悪名高い bug 858 は、このような機能の wishlist として見なされています。この機能のためのコードは CAPS(capabilities:機能)と呼ばれています。最後に IE のゾーンという考え方は、このアイデアの一部を利用しています。

この文書は JavaScript に精通したプログラマを対象にしています。

注意:Mozilla 0.9.9 の段階では、ゾーンポリシーを作成するためには "policynames" ラインが必要です。詳細は以下を参照してください。

グローバルポリシーを設定する

ポップアップ広告に悩まされていて、全てのウェブページで新しいブラウザウィンドウを開かないように設定したい場合を考えてみましょう。これは Mozilla ユーザ設定ファイル(user.js)に以下の行を加えれば設定することができます:

user_pref("capability.policy.default.Window.open", "noAccess");

Window.opennoAccess に設定することで、ウェブページは Window タイプのあらゆるオブジェクトの open プロパティにアクセスできなくなります。ウェブページが window.open()(または open())を使って新しいウィンドウを開こうとすると、失敗します。セキュリティマネージャが JavaScript 例外を投げ、この機能を呼び出せないようにするからです。ウェブページがこの例外を取り込まない限り、スリクプとは停止し、JavaScript コンソールにエラーメッセージ(Tasks->Tools->JavaScript Console)が表示されます。

ゾーンポリシー

default は特別です。なぜなら全てのサイトに適用されるからです。このディフォルト設定を上書きする形で、特定のサイトやサイト群に対してポリシーを設定することもできます。例えば、www.evil.org や www.annoying.com ではダイアログ・ウィンドウを表示させないようにするには、次のようなコードを利用することもできます:

user_pref("capability.policy.policynames", "strict");
user_pref("capability.policy.strict.sites", "http://www.evil.org http://www.annoying.com");
user_pref("capability.policy.strict.Window.alert", "noAccess");
user_pref("capability.policy.strict.Window.confirm", "noAccess");
user_pref("capability.policy.strict.Window.prompt", "noAccess");

最初の行で、作成したいポリシーの名前を定義しています。この例では "strict" です。複数のポリシーを定義したい場合は、同じ行に全て書き込んでください。以下のような感じです:

user_pref("capability.policy.policynames", "strict, shoppingsites, ");

"capability.policy.strict.sites" 設定ではウェブサイトでどの strict ポリシーを適用するかを定義します。この設定の値はサイトのリスト(プロトコルとホスト名のみ)です。スペースで区切ってください。最後の三行では制限ポリシーを定義しています。これらのサイトに対して、上の例では window.alert()window.confirm()、そして window.prompt() にアクセスできないようにしています。

strict ポリシー下のサイトが window.open() を使って新しいウィンドウを開くことができるかは定義されていないので、ディフォルトのポリシーが依然として適用されることに注意してください。

window.open() へのアクセスをブロックすることで、www.usefulsite.net でもスクリプトが作動しなくなってしまった場合を考えてみましょう。このページに対しては、Window.open ポリシーをディフォルトの値である sameOrigin に戻すように設定することで、window.open 制限を迂回できるようにすることができます:

user_pref("capability.policy.policynames", "trustable");
user_pref("capability.policy.trustable.sites", "http://www.usefulsite.net");
user_pref("capability.policy.trustable.Window.open", "sameOrigin");

ポリシーの名前は何でも構いません。この例では stricttrustable を利用しました。しかし blacklistmypolicy といったものでも構いません。

セキュリティレベル

三つの特別なセキュリティレベルがあります:

  • noAccess:ウェブサイトはこのプロパティにアクセス、あるいはこの機能を呼び出すことは絶対できません。
  • sameOrigin(ディフォルト):ウェブページはこのプロパティにアクセスすることができますが、同一サイトのページにのみアクセスできます。Mozilla が二つのページを同一サイトにあるかどうかをどのように判断しているかについての説明は こちらの文書 を参照してください。
  • allAccess:ウェブサイトは、同一サイトまたはあらゆるサイトでもこのプロパティにアクセスすることができます。

セキュリティレベルが上記三つのどれにも当てはまらない場合は、privilege 名として扱われ、スクリプトは、署名 され且つユーザがダイアログを通じてスクリプトに権限を与えた場合にのみ、アクセスすることができます。

Get と Set

プロパティ名の後に .get.set を追加すると、プロパティの読み込みのみや、プロパティの値の変更のみに対して適用できるポリシーを指定することができます。これで、あるポリシーではプロパティを読み込み、別のプロパティではその値を変更するように指定することができます。ページが値を設定できないようにしつつ、読み込むことはできるようにする例を 下のセクション で見てください。

Class.property.getClass.property.set を同じレベルに設定すると、Class.property をそのレベルに設定することと同じことになります。ファンクションの名前の後には getset(例: openwrite)を使わないでください。なぜなら、"get" や "set" のコンセプトは、ファンクション ではない プロパティ(例:bgColorlocation)にのみ適用されるからです。

オブジェクト名を特定する

使用する正しいオブジェクト名を特定するのは、時として困難です。例えば、あるウェブページがフォームを送信できないようにしたい、しかしフォーム要素のクラス名を知らない、という場合を考えてみましょう。最も簡単な方法は、オブジェクトを文字列に変換するスクリプトを書くことです。フォームを持つページに行って、ロケーションバーに javascript:alert(document.forms[0]) と入力すれば、document.forms[0][xpconnect wrapped HTMLFormElement] であることが分かるでしょう。HTMLFormElement はクラスの名前で、HTMLFormElement.submitnoAccess に設定して、ウェブページが form.submit を利用してフォームを送信できないようにします。

HTMLAnchorElement といった要素の中には、クラス名を簡単に見つけられなくするような特殊な toString ファンクションを持つものがあります。ロケーションバーに javascript:alert(document.links[0]) に入力すると、クラス名ではなく、最初のリンクの URL が表示されるはずです。この問題を回避するには、document.links[0] オブジェクトに対してディフォルトの toString ファンクションを利用することです。なので:javascript:alert(window.toString.apply(document.links[0])) となります。

警告:プロパティの中には複数のアクセスパスを持っているものがある

プロパティへのアクセスをブロックする際、HTML 要素の属性のようにプロパティによってはアクセスする方法が複数あるということを覚えておいてください。これは重要です。例えば、ユーザが www.evil.org からのスクリプトが HTML アンカータグ (<A HREF="...">)href 属性にアクセスできないようにしたい場合を考えてみてください。次のような prefs では不十分です:

user_pref("capability.policy.policynames", "nohrefs");
user_pref("capability.policy.nohrefs.sites", "http://www.evil.org");
user_pref("capability.policy.nohrefs.HTMLAnchorElement.href", "noAccess");

上記の prefs では www.evil.org 上のスクリプトが document.links[1].href にアクセスできないようにはしますが、このスクリプトは、DOM 2 のシンタックスである document.links[1].attributes.getNamedItem("href")document.links[1].getAttribute("href") を使って、全く同じ情報にアクセスすることができるのです。次の prefs であれば href 属性へのアクセスを完全にブロックすることができます:

user_pref("capability.policy.policynames", "nohrefs");
user_pref("capability.policy.nohrefs.sites", "http://www.evil.org");
user_pref("capability.policy.nohrefs.HTMLAnchorElement.href", "noAccess");
user_pref("capability.policy.nohrefs.HTMLAnchorElement.attributes", "noAccess");
user_pref("capability.policy.nohrefs.HTMLAnchorElement.getAttribute", "noAccess");
user_pref("capability.policy.nohrefs.HTMLAnchorElement.getAttributeNS", "noAccess");

一般的なルールとして、属性へのアクセスをブロックするためには、attributes プロパティや getAttribute および getAttributeNS メソッドへのアクセスもブロックしなければなりません。

完全な設定シンタックス

JavaScript のセキュリティポリシーに関してのシンタックスのより正式なステートメントを掲載します:

  • ポリシーは ポリシー名ラインサイトライン、そして単数・複数の ポリシーライン から成ります。default ポリシーの場合は サイトライン を飛ばしてください。ただし、他の全ての部分では必要です。

  • ポリシー名ライン では定義したい全てのポリシーの名前を指定します。定義するポリシーが幾つあろうと、ポリシー名ラインは一行のみにしなければ成りません。次のような形式になります:
    user_pref("capability.policy.policynames", "<list of policy names>");
    <list of policy names> となっている部分は、定義したいポリシー名のリストです。コンマや空白で分けます。

  • サイトライン は次のような形式になります:
    user_pref("capability.policy.<policy name>.sites","<URL list>");
    • <policy name> は文字と数字のあらゆる組み合わせが可能です。但し文字で始めてください。
    • "<URL list> は URL のリストです。空白で区切ってください。リスト内の各 URL は、定義されたプロトコル(例:http:)を使用する全ての URL に適用される protocol:、または特定のホスト(例:http://www.annoyingsite.myisp.com)に適用される protocol://host とすることができます。URL のパス部分(ホスト名の / やそれ以降のいずれか)を含めないようにしてください。

  • ポリシー名 は次のような形式になります:
    user_pref("capability.policy.<policy name>.<class name>.<property name>","allAccess | noAccess | sameOrigin | <capability name>");
    • <policy name> はサイトライン上のポリシー名と同じでなければなりません。
    • pref の値(allAccess など)は上で解説しています。

あるサイトの全ての JavaScript を無効にする

特殊なプロパティ javascript.enabled は JavaScript の実行を不能にするために利用することができます。default ポリシーを使ってグローバルに、またはサイトポリシーを使ってサイト群に対して適用することができます。設定の値は "noAccess""allAccess" にしなければなりません。これ以外の値では動作しません。次の例は、site1.com と site2.com で全ての JavaScript の実行を不能にします:

user_pref("capability.policy.policynames", "nojs");
user_pref("capability.policy.nojs.sites", "http://site1.com http://site2.com");
user_pref("capability.policy.nojs.javascript.enabled", "noAccess");

次の例では goodsite.com を除く全てのサイトで JavaScript の実行を不能にします:

user_pref("capability.policy.policynames", "jsok");
user_pref("capability.policy.default.javascript.enabled", "noAccess");
user_pref("capability.policy.jsok.sites", "http://goodsite.com");
user_pref("capability.policy.jsok.javascript.enabled", "allAccess");

"allAccess" または "noAccess" という値だけが javascript.enabled ポリシー prefs では有効だということに注意してください。この場合に "sameOrigin" や他の文字列を使用しないでください。また、次の設定:

user_pref("javascript.enabled", false);

は、全てのサイトに対して capability.policy.default.javascript.enabled を含め すべての capability.policy をオーバーライドすることにも注意してください。

追加例

ウェブページがブラウザ・ウィンドウのサイズを変更できないようにする

user_pref("capability.policy.default.Window.innerWidth.set", "noAccess");
user_pref("capability.policy.default.Window.innerHeight.set", "noAccess");
user_pref("capability.policy.default.Window.outerWidth.set", "noAccess");
user_pref("capability.policy.default.Window.outerHeight.set", "noAccess");
user_pref("capability.policy.default.Window.sizeToContent", "noAccess");
user_pref("capability.policy.default.Window.resizeTo", "noAccess");
user_pref("capability.policy.default.Window.resizeBy", "noAccess");

ウェブページがブラウザ・ウィンドウの位置を変更できないようにする

user_pref("capability.policy.default.Window.screenX.set", "noAccess");
user_pref("capability.policy.default.Window.screenY.set", "noAccess");
user_pref("capability.policy.default.Window.moveTo", "noAccess");
user_pref("capability.policy.default.Window.moveBy", "noAccess");

ウェブページが使用している解像度や色設定を検知できないようにする

(注:以下のラインでは画像解像度を検知する全ての方法をブロックする訳ではありません。最も一般的な方法しかブロックしません。また以下のラインでは、ウェブページがウィンドウサイズの大きさを検知するのを防ぐことはできません。)

user_pref("capability.policy.default.Screen.top", "noAccess");
user_pref("capability.policy.default.Screen.left", "noAccess");
user_pref("capability.policy.default.Screen.width", "noAccess");
user_pref("capability.policy.default.Screen.height", "noAccess");
user_pref("capability.policy.default.Screen.pixelDepth", "noAccess");
user_pref("capability.policy.default.Screen.colorDepth", "noAccess");
user_pref("capability.policy.default.Screen.availWidth", "noAccess");
user_pref("capability.policy.default.Screen.availHeight", "noAccess");
user_pref("capability.policy.default.Screen.availLeft", "noAccess");
user_pref("capability.policy.default.Screen.availTop", "noAccess");

ウェブページがステータスバーの文字列を変更できないようにする

ウェブページの中には、リンクにマウスカーソルを合わせた時に、ステータスバーのテキストを変えて「ブラインド・リンク」を作り、ステータスバーにリンクアドレスを表示させないようにするものがあります。以下の行で多くのブラインド・リンクを通常のリンクにすることができます。

user_pref("capability.policy.default.Window.status", "noAccess");

ユーザインターフェース

セキュリティポリシーを設定するためのユーザインタフェースはできていません。将来、設定パネルに、ユーザが user.js を手動で編集することなく、また JavaScript の知識がなくてもポリシーを設定できる専用のパネルを備えたいと考えています。これが機能の実装において最も難しい部分になる見込です。bug 38966 を参照してください。