サンドボックス化された iframe で安全にプレイ

今日のウェブで豊かなエクスペリエンスを構築するには、ほぼ必然的に エンベディング コンポーネントやコンテンツをユーザーが制御できない状態にします。 サードパーティ ウィジェットはエンゲージメントを促進し、 ユーザーエクスペリエンスが重視され ユーザー作成コンテンツは おすすめコンテンツが表示されますどちらかを断つことは現実的ではありませんが、 どちらの場合も、サイトでなんらかの不正 TM が発生するリスクが高まります。各 広告やソーシャル メディアのウィジェットなど、 攻撃者の侵入経路:

コンテンツ セキュリティ ポリシー (CSP) 両方のコンテンツに関連するリスクを軽減するために、 スクリプトなどの信頼できるソースを許可リストに登録し、 説明します。これは正しい方向への大きな一歩ですが、 ほとんどの CSP ディレクティブが提供している保護はバイナリです。つまり、リソースは できます。場合によっては、「 このコンテンツ ソースを信頼できることは確かですが、すごくきれいですね。埋め込む 「でもサイトが壊れないように」と言われました。

最小権限

基本的に、YouTube はコンテンツに対して権利を付与できる仕組みを その職務に必要な最小限の能力しか組み込まないでください。ウィジェットが 新しいウィンドウをポップアップする必要がなく、window.open へのアクセスが 負傷した。Flash が不要な場合、プラグインのサポートをオフにしても、 困難です。Google は、最小権限の原則に従うことで、セキュリティを最大限に高める 権限、ブロック 必要とする機能に直接関係のない各機能に 使用できます。その結果、データ アナリストは、 使用すべきでない権限が悪用されることはないからです。これは、 そもそもアクセスできません

iframe 要素は、そのようなソリューションの適切なフレームワークへの第一歩です。 信頼できないコンポーネントを iframe に読み込むと、分離の尺度が提供される ロードしたいコンテンツとの間の 通信パスを指定しますフレーム内のコンテンツ ページの DOM、ローカルに保存したデータにはアクセスできず、 ページ上の任意の位置に描画できるスコープは Chronicle の 調整できます。しかし、この分離は実際には堅牢ではありません。含まれているページ わずらわしい動作や悪意のある動作に対処するためのオプションが依然として数多く存在します。たとえば、自動再生 動画、プラグイン、ポップアップはほんの一例です。

iframe 要素の sandbox 属性 は、フレーム付きコンテンツの制限を厳しくするために必要なものを提供してくれます。Google では、 特定のフレームのコンテンツを低権限で読み込むようにブラウザに指示する そのために必要な機能のサブセットのみが、 サポートします。

要確認、ただし確認

Twitter の「ツイート」ボタンは機能の良い例であり、 サンドボックスを使用してサイトに安全に埋め込むことができます。Twitter では、 ボタンをクリックする これを次のコードに置き換えます。

<iframe src="https://platform.twitter.com/widgets/tweet_button.html"
        style="border: 0; width:130px; height:20px;"></iframe>

何がロックダウンできるのかを知るために、 必要があります。フレームに読み込まれた HTML は、 Twitter のサーバーから JavaScript を呼び出し、 クリックすると表示されますこのインターフェースは、Twitter の ツイートを正しいアカウントに結び付けるために Cookie を使用します。また、 ツイート フォームを送信します。これで終わりです。フレームが必ずしも トップレベル ウィンドウに移動したり、プラグインを 多くの機能が用意されています。このような権限は必要ないので、 フレームのコンテンツをサンドボックス化して削除しましょう。

サンドボックス化はホワイトリストに基づいて機能します。まず 追加することで個々の機能を再び有効にできます。 特定のフラグをサンドボックスの構成に追加します。Twitter ウィジェットでは JavaScript、ポップアップ、フォーム送信、Twitter.com の できます。これを行うには、iframesandbox 属性を追加して、 次の値を使用します。

<iframe sandbox="allow-same-origin allow-scripts allow-popups allow-forms"
    src="https://platform.twitter.com/widgets/tweet_button.html"
    style="border: 0; width:130px; height:20px;"></iframe>

以上です。フレームには必要な機能がすべて与えられ、 想定していないすべての権限へのアクセスは拒否され、 sandbox 属性の値を介して明示的に付与する。

機能のきめ細かな制御

上記の例では、可能なサンドボックス フラグがいくつか見てきました。では次に、 属性の内部の仕組みをもう少し詳しく調べることができます。

iframe で sandbox 属性が空の場合、フレーム内のドキュメントは完全にサンドボックス化され、 次の制限が適用されます。

  • JavaScript はフレーム内のドキュメントで実行されません。これには スクリプト タグを介して明示的に読み込まれた JavaScript と、インライン イベント ハンドラ および javascript: URL を指定します。つまり、noscript タグに含まれるコンテンツも ユーザーが自分でスクリプトを無効にした場合と同じように表示されます。
  • フレーム内のドキュメントは固有のオリジンに読み込まれます。つまり、 同一オリジン チェックが失敗します。一意のオリジンは、他のオリジンと できます。これは特に、ドキュメントに一切影響がない 任意の送信元の Cookie またはその他のストレージ メカニズムに保存されているデータへのアクセス (DOM ストレージ、インデックス付き DB など)。
  • フレーム内のドキュメントでは、新しいウィンドウやダイアログを作成できません(window.open または target="_blank" など)。
  • フォームを送信できません。
  • プラグインは読み込まれません。
  • フレーム内のドキュメントは自身の移動のみが可能で、最上位の親ドキュメントは移動できません。 window.top.location を設定すると例外がスローされ、次の内容を含むリンクをクリックすると例外がスローされます。 target="_top" は無視されます。
  • 自動的にトリガーされる機能(オートフォーカスされたフォーム要素、自動再生) 動画など)がブロックされます。
  • ポインタのロックを取得できません。
  • フレーム内のドキュメントに含まれる iframesseamless 属性は無視されます。

これは非常に厳格で、ドキュメントは完全にサンドボックス化された iframe に読み込まれています。 リスクはほとんどありませんもちろん、これだけでは大きな価値はありません。 静的コンテンツを完全にサンドボックスで解決できるかもしれませんが 状況を少し緩めます

プラグインを除き、これらの制限はそれぞれ、 sandbox 属性の値にフラグを追加します。サンドボックス化されたドキュメントは プラグインを実行する。プラグインはサンドボックス化されていないネイティブ コードだが、それ以外はすべて公平 ゲーム:

  • allow-forms でフォームの送信を許可します。
  • allow-popups では、(衝撃的な)ポップアップが表示されます。
  • allow-pointer-lock を使用すると、ポインタのロックが可能になります。
  • allow-same-origin を使用すると、ドキュメントのオリジンを維持できます。ページが読み込まれました https://example.com/ からのアクセスは、そのオリジンのデータに引き続きアクセスできます。
  • allow-scripts を使用すると、JavaScript の実行が可能になります。また、 自動的にトリガーされるようにします(JavaScript での実装は簡単であるため)。
  • allow-top-navigation を使用すると、ドキュメントがフレーム外に 最前面のウィンドウを操作します

これらを念頭に置くことで、なぜ特定の Pod が 上記の Twitter サンプルのサンドボックス フラグのセット:

  • allow-scripts が必要です。これは、フレームに読み込まれたページによっていくつかの処理が実行されるためです。 ユーザー操作を処理する JavaScript。
  • このボタンをクリックすると新しいツイート フォームがポップアップ表示されるため、allow-popups は必須です。 クリックします。
  • ツイート フォームは送信可能であるため、allow-forms は必須です。
  • twitter.com の Cookie が使用されるように、allow-same-origin は必須です アクセスできない、ユーザーがログインしてフォームを投稿できない、といった問題です。

注意すべき重要な点は、フレームに適用されるサンドボックス フラグも サンドボックスで作成されたすべてのウィンドウまたはフレームに適用されます。つまり フォームが存在する場合でも、フレームのサンドボックスに allow-forms を追加する ウィンドウ内にそのフレームがポップアップ表示され、

sandbox 属性を設定すると、ウィジェットは対象の権限のみを取得します。 プラグイン、トップ ナビゲーション、ポインタのロックなどの機能はそのまま ブロックされています。ウィジェットを埋め込むことで、悪影響を及ぼすリスクを低減しました。 これは関係者全員のメリットです

権限の分離

サードパーティのコンテンツをサンドボックス化して、信頼できないコードを 明らかに有益です。では、 どうすればよいでしょうか。自分自身を信頼しているわよね。では、サンドボックスが重要な理由は何でしょうか。

私はその質問を変えます。「コードでプラグインを必要としないのなら、なぜプラグインを プラグインへのアクセス権が必要ですか?せいぜい決して使えない特権、最悪の場合には 攻撃者が足を踏み入れるための侵入経路となります。皆のコードに ほぼすべてのアプリケーションが 1 つの方法で悪用に対して脆弱になります。 できます。独自のコードをサンドボックス化すると、攻撃者が アプリケーションが破壊されると、その攻撃者にはアプリケーションへのフルアクセス権が アプリケーションのオリジン実行可能な操作はアプリケーションで できます。まだ悪くはないが、本来の悪さはない

このリスクをさらに軽減するには、アプリケーションを 必要最小限の権限で各部分をサンドボックス化します。 これはネイティブ コードで非常によく使われる手法です。たとえば Chrome では、 ローカルのハードドライブにアクセスできる高権限のブラウザプロセスに移行 ネットワーク接続や権限の低い多くのレンダラ プロセスが 手間のかかるコンテンツを解析できますレンダラは編集や 必要なすべての情報がブラウザによって 表示されます。巧妙なハッカーがレンダラを壊す方法を見つけたとしても、 レンダラ自体はそれほど重要な処理を行えないため、それほど進められていません。 高い権限のアクセスはすべて、ブラウザのプロセスを介してルーティングされる必要があります。 攻撃者はシステムのさまざまな部分に穴をいくつか見つける必要がある 侵害を受けるリスクを大幅に軽減できます。

eval() を安全にサンドボックス化

サンドボックスと postMessage API: このモデルが成功しているかどうかをウェブに応用するのは非常に簡単です。ピース アプリケーションはサンドボックス化された iframe に配置でき、親ドキュメントは ブローカー通信を行うため、メッセージを投稿し、 できます。このように 構成されている仕組みにより 最小限に抑える必要があります。また、セキュリティ管理を 統合ポイントが明確になり、ソリューションのどの部分が必要かを正確に把握できる 入出力の検証に注意する必要があります。玩具の例を見てみましょう どうなるか見てみましょう

Evalbox はエキサイティングなアプリケーション これは文字列を受け取り、それを JavaScript として評価します。そうですか。目的 長い間待っていることでしょうかなり危険です。 言うまでもなく、任意の JavaScript の実行を許可するということは、 オリジンが提供するすべてのデータは取得可能ですGoogle Cloud で サンドボックス内でコードを確実に実行することで、 かなり安全になりましたこれから、 まずはフレームの内容から始めます。

<!-- frame.html -->
<!DOCTYPE html>
<html>
    <head>
    <title>Evalbox's Frame</title>
    <script>
        window.addEventListener('message', function (e) {
        var mainWindow = e.source;
        var result = '';
        try {
            result = eval(e.data);
        } catch (e) {
            result = 'eval() threw an exception.';
        }
        mainWindow.postMessage(result, event.origin);
        });
    </script>
    </head>
</html>

フレーム内には、メッセージをリッスンするだけの最小限のドキュメントが含まれています。 window オブジェクトの message イベントにフックすることで、親から親からも削除されます。 親が iframe のコンテンツで postMessage を実行するたびに、このイベントは これにより、親が要求している文字列に 実行されます。

ハンドラでは、イベントの source 属性(親)を取得します。 クリックします。結果をお送りしますので、 できます。面倒な処理は、モデルに渡したデータを eval()。この呼び出しは、禁止されたオペレーションとして try ブロックでラップされています サンドボックス化された iframe 内では、頻繁に DOM 例外が生成されます。CANNOT TRANSLATE 代わりにわかりやすいエラー メッセージで報告してください。最後に、結果を 親ウィンドウに戻ります。これはとても簡単です。

親も同様にシンプルです。textarea を含む小さな UI を作成します。 button 実行用があり、frame.html サンドボックス化された iframe で、スクリプトの実行のみを許可します。

<textarea id='code'></textarea>
<button id='safe'>eval() in a sandboxed frame.</button>
<iframe sandbox='allow-scripts'
        id='sandboxed'
        src='frame.html'></iframe>

では、実行に向けて準備しましょう。まず、Pub/Sub から返されたレスポンスを iframealert() をユーザーに公開します。おそらく実際のアプリケーション 次のようにすることで、わずらわしさを軽減できます。

window.addEventListener('message',
    function (e) {
        // Sandboxed iframes which lack the 'allow-same-origin'
        // header have "null" rather than a valid origin. This means you still
        // have to be careful about accepting data via the messaging API you
        // create. Check that source, and validate those inputs!
        var frame = document.getElementById('sandboxed');
        if (e.origin === "null" &amp;&amp; e.source === frame.contentWindow)
        alert('Result: ' + e.data);
    });

次に、button をクリックするためのイベント ハンドラを接続します。ユーザーが クリックが検出されると、textarea の現在の内容を取得して、 使用します。

function evaluate() {
    var frame = document.getElementById('sandboxed');
    var code = document.getElementById('code').value;
    // Note that we're sending the message to "*", rather than some specific
    // origin. Sandboxed iframes which lack the 'allow-same-origin' header
    // don't have an origin which you can target: you'll have to send to any
    // origin, which might alow some esoteric attacks. Validate your output!
    frame.contentWindow.postMessage(code, '*');
}

document.getElementById('safe').addEventListener('click', evaluate);

簡単ですよね。非常にシンプルな評価 API を作成しました。これにより、 評価対象のコードが、Cookie などの機密情報にアクセスできない DOM ストレージがありません同様に、評価されたコードでは、プラグインの読み込み、新しいウィンドウの表示、 その他の迷惑な活動や悪意のある活動。

モノリシック アプリケーションを 単一目的のコンポーネントのみを使用できます。各メッセージを単純なメッセージング API でラップできます。 必要があります高い権限を持つ親ウィンドウは、 コントローラとディスパッチャがあり、それぞれが特定のモジュールに ジョブの実行、結果をリッスンする最小限の権限、 各モジュールに必要な情報のみが適切に供給されるようにします。

ただし、フレームで構成されたコンテンツを扱うときは細心の注意を払う必要があるので注意してください。 親と同じオリジンから派生しますあるページが https://example.com/ がサンドボックスを使って同じオリジンの別のページをフレーム化しています allow-same-origin フラグと allow-scripts フラグの両方を含む フレーム内に収めたページから親まで到達し、Sandbox の属性を削除できる 提供します

サンドボックスでプレイ

サンドボックス化は、Firefox 17 以降、 IE10 以降、および Chrome について記述しています(もちろん、caniuse は サポート テーブルを参照)。sandbox の適用 iframes 属性にこの属性を含めると、そのプロジェクトに特定の権限を付与できます。 コンテンツに対して必要な権限のみを コンテンツが正しく機能しないことがあります。これにより、リスクを低減する 第三者のコンテンツのインクルージョンに関連する コンテンツ セキュリティですでに実現できる ポリシーをご覧ください。

さらに、サンドボックス化は、巧妙な攻撃が仕掛けられても 攻撃者がデベロッパーのコードの穴を悪用できます。を分離することで、 モノリシック アプリケーションを一連のサンドボックス サービスに 小さな自己完結型の機能によって、攻撃者は 特定のフレームのみにそのコンテンツ管理者もいますそれは 特に、コントローラを大幅に削減できるため、 あります。セキュリティ関連の作業に時間をかけると、そのコードの監査に 後はブラウザで聞くようにしましょう

だからといって、サンドボックスがセキュリティの問題を解決し、 セキュリティを確保できます。多層防御を提供します。 ユーザーの権限をブラウザ サポートを利用することは、まだ ユーザー(ユーザー クライアントを管理している場合。エンタープライズ環境、 など)。いずれは...ただし今のところ、サンドボックスは 強化するためのソリューションである一方、 頼りにできますそれでも、レイヤは優れています。この方法をおすすめします。 1 です。

関連情報

  • HTML5 アプリケーションでの権限分離 小さなフレームワークの設計を通じて 既存の 3 つの HTML5 アプリ

  • 他の 2 つの新しい iframe と組み合わせることで、サンドボックス化の柔軟性を高める 属性: srcdoc、 および seamless。 前者を使用すると、追加のオーバーヘッドを発生させることなくフレームにコンテンツを入力できます。 後者ではフレーム内のコンテンツにスタイルを合わせることができます 現在のところ、どちらのブラウザもサポートが不十分です(Chrome と WebKit) 。将来的には興味深い組み合わせになるでしょう。ご興味はおありでしょうか。 たとえば、次のコードを使用して、記事のコメントをサンドボックス化します。

        <iframe sandbox seamless
                srcdoc="<p>This is a user's comment!
                           It can't execute script!
                           Hooray for safety!</p>"></iframe>