序文: サンドボックスといえば、私たちの頭には反射的に上の写真が思い浮かび、すぐに興味がわいてくるかもしれませんが、残念ながらこの記事には「Minecraft」(昔のカバーパーティー)は関係ありません。次の記事では、「Browser World」のサンドボックスを徐々に紹介していきます。 1. サンドボックスとは何ですか?コンピュータ セキュリティにおいて、 たとえば、次のシナリオにはサンドボックスの抽象的な概念が関係しています。
2. サンドボックスの適用シナリオは何ですか?上記では、比較的マクロなサンドボックス シナリオをいくつか紹介しましたが、実際には、日常的な開発では、このようなメカニズムの適用を必要とするシナリオが数多くあります。
つまり、信頼できないサードパーティのコードに遭遇した場合でも、サンドボックスを使用してコードを分離し、外部プログラムの安定した動作を確保することができます。信頼できないコードが何の処理もせずに実行されると、フロントエンドにおける最も明らかな副作用/損害は、グローバル // サブアプリケーションコード window.location.href = 'www.diaoyu.com' Object.prototype.toString = () => { console.log('あなたは愚か者です:)') } document.querySelectorAll('div').forEach(node => node.classList.add('hhh')) リクエストを送信します(ドキュメント.cookie) ... 3. JSサンドボックスの実装方法サンドボックスを実装するには、実際にはプログラム実行メカニズムを開発する必要があり、このメカニズムの動作により、サンドボックス内のプログラムの動作は外部プログラムの動作に影響を与えません。 3.1 最もシンプルなサンドボックスこの効果を達成するための最も直接的なアイデアは、プログラム内でアクセスされるすべての変数が、グローバル実行環境から値を取得するのではなく、信頼できるまたは自律的なコンテキスト環境から取得されることです。次に、すべての変数が信頼できるコンテキスト環境からアクセスされるようにするには、 プログラムを実行するためのスコープを構築する必要があります。 //実行コンテキストオブジェクト const ctx = 関数: 変数 => { console.log(変数) }, フー: 'フー' } // 最も単純なサンドボックス関数poorestSandbox(code, ctx) { eval(code) // プログラムを実行するための関数スコープを構築します} // 実行するプログラム const code = ` ctx.foo = 'バー' ctx.func(ctx.foo) ` povertySandbox(code, ctx) // バー このようなサンドボックスでは、ソース プログラムが変数を取得するときに実行コンテキスト オブジェクトのプレフィックスを追加する必要がありますが、第三者の動作を制御する方法がないため、これは明らかに非常に不合理です。このプレフィックスを削除する方法はありますか? 3.2 非常にシンプルなサンドボックス(あり) //実行コンテキストオブジェクト const ctx = { 関数: 変数 => { console.log(変数) }, フー: 'フー' } // 非常に貧弱なサンドボックス function veryPoorSandbox(code, ctx) { with(ctx) { // 追加 評価(コード) } } // 実行するプログラム const code = ` foo = 'バー' 関数foo ` veryPoorSandbox(code, ctx) // バー これにより、実行中のプログラム内の変数が、外部実行環境の前にサンドボックスによって提供されるコンテキストで検索されるという効果が得られます。 問題は、提供されたコンテキスト オブジェクトで変数が見つからない場合でも、コードはスコープ チェーンをレイヤーごとに検索し続けることです。このようなサンドボックスでは、内部コードの実行を制御できません。サンドボックス内のコードでは、手動で提供されたコンテキスト オブジェクト内の変数のみを検索し、コンテキスト オブジェクト内に変数が存在しない場合はエラーを報告するか、 3.3 それほど単純ではないサンドボックス(プロキシあり)上記の問題を解決するために、 has は // 実行するコードをラップする with を構築し、with コードブロックの関数インスタンスを返します function withedYourCode(code) { コード = 'with(globalObj) {' + コード + '}' 新しい関数('globalObj'、コード)を返します } // アクセスできるグローバルスコープのホワイトリスト const access_white_list = ['Math', 'Date'] // 実行するプログラム const code = ` Math.random() location.href = 'xxx' 関数foo ` //実行コンテキストオブジェクト const ctx = { 関数: 変数 => { console.log(変数) }, フー: 'フー' } // 実行コンテキストオブジェクトのプロキシオブジェクト const ctxProxy = new Proxy(ctx, { has: (target, prop) => { // has は with コード ブロック内の任意のプロパティへのアクセスをインターセプトできます if (access_white_list.includes(prop)) { // アクセス可能なホワイトリストでは、上方向に検索を続けることができます return target.hasOwnProperty(prop) } ターゲットが独自のプロパティを持っている場合、 throw new Error(`無効な式 - ${prop}! これは実行できません!`) } 真を返す } }) // それほど貧弱ではないサンドボックス function littlePoorSandbox(code, ctx) { withedYourCode(code).call(ctx, ctx) // これを手動で構築されたグローバル プロキシ オブジェクトにポイントします} littlePoorSandbox(コード、ctxProxy) // キャッチされないエラー: 無効な式 - 場所! それはできません! この時点で、比較的単純なシナリオの多くはカバーできます ( これにより、別の疑問が生じます。サブルーチンが外部のグローバル状態に影響を与えずにすべてのグローバル オブジェクトを使用できるようにするにはどうすればよいでしょうか。 3.4 ナチュラルな高品質サンドボックス(iframe)上記の質問を聞いたとき、私はすぐに自分を専門家と呼びました。iframe 次のようなシナリオを想像してください。ページ内に複数のサンドボックス ウィンドウがあり、そのうちの 1 つはメイン ページといくつかのグローバル状態を共有する必要があり (例: ブラウザーの戻るボタンをクリックすると、サブアプリケーションも前のレベルに戻ります)、もう 1 つのサンドボックスはメイン ページといくつかの他のグローバル状態を共有する必要があります (例: Cookie のログイン状態を共有します)。 ブラウザはメインページと 3.5 ではサンドボックスを使用できるはずです (プロキシ + iframe 付き)上記のシナリオを実現するには、上記の方法を組み合わせることができます。
//サンドボックスグローバルプロキシオブジェクトクラス class SandboxGlobalProxy { コンストラクター(共有状態) { // iframe オブジェクトを作成し、ネイティブ ブラウザのグローバル オブジェクトをサンドボックスのグローバル オブジェクトとして取り出します。const iframe = document.createElement('iframe', {url: 'about:blank'}) document.body.appendChild(iframe) const sandboxGlobal = iframe.contentWindow // サンドボックスランタイムのグローバルオブジェクト return new Proxy(sandboxGlobal, { has: (target, prop) => { // has はコードブロック内の任意のプロパティへのアクセスを傍受できます if (sharedState.includes(prop)) { // プロパティが共有グローバル状態に存在する場合は、プロトタイプチェーンに沿って外側のレイヤーを検索します return false } ターゲットが独自のプロパティを持っている場合、 throw new Error(`無効な式 - ${prop}! これは実行できません!`) } 真を返す } }) } } 関数 maybeAvailableSandbox(コード, ctx) { withedYourCode(code).call(ctx, ctx) } 定数code_1 = ` console.log(history == window.history) // false window.abc = 'サンドボックス' オブジェクト.prototype.toString = () => { console.log('トラップされました!') } console.log(window.abc) // サンドボックス ` const sharedGlobal_1 = ['history'] // 外部実行環境と共有するグローバルオブジェクト const globalProxy_1 = new SandboxGlobalProxy(sharedGlobal_1) おそらく利用可能なサンドボックス(code_1、globalProxy_1) window.abc // 未定義 Object.prototype.toString() // [object Object] は印刷されません Traped サンプルコードの結果から、 3.6 サンドボックスエスケープサンドボックスは作成者にとってはセキュリティ戦略ですが、ユーザーにとっては制約となる可能性があります。創造的な開発者は、さまざまな方法でこの制約を取り除こうとしますが、これはサンドボックス エスケープとも呼ばれます。したがって、サンドボックス プログラムにとって最大の課題は、これらの予期しないプログラムの実行をどのように検出し、禁止するかということです。 上記で実装したサンドボックスは、私たちのニーズを満たしているようです。これで完了でしょうか?実際には、以下の操作はサンドボックス外の環境に影響を与え、サンドボックスからの脱出を実現します。 サンドボックス実行コンテキスト内のオブジェクトの内部プロパティにアクセスする場合、 // サンドボックスオブジェクト内のオブジェクトのプロパティにアクセスする場合、上記のコードの一部は省略されます const ctx = { ウィンドウ: { 親: {...}、 ... } } 定数コード = ` ウィンドウ.親.abc = 'xxx' ` ウィンドウ.abc // xxx
定数コード = ` ({}).コンストラクタ.プロトタイプ.toString = () => { console.log('脱出!') } ` ({}).toString() // エスケープ! [object Object] が必要です 3.7 「完璧な」サンドボックス(インタープリターのカスタマイズ)上記の方法でサンドボックスを実装すると、多かれ少なかれ欠陥があります。完成に近いサンドボックスはありますか? 実際、多くのオープンソースライブラリは、ソースプログラム構造を分析して各ステートメントの実行ロジックを手動で制御するという、この手法をすでに行っています。このようにして、プログラムの実行時間を指定するコンテキストと、サンドボックスの制御を逃れようとする操作をキャプチャするコンテキストの両方が制御されます。このようなサンドボックスを実装することは、本質的にはカスタム インタープリターを実装することです。 関数almostPerfectSandbox(コード、ctx、違法操作) { return myInterpreter(code, ctx,illegalOperations) // カスタムインタープリター } 4. まとめこの記事では、主にサンドボックスの基本的な概念とアプリケーション シナリオを紹介し、JavaScript サンドボックスの実装方法について考えていきます。サンドボックスの実装方法は静的なものではなく、その目標は特定のシナリオと組み合わせて分析する必要があります。さらに、サンドボックスからの脱出を防ぐことも、構築の初期段階ですべての実行 Minecraft のように、サンドボックスは一晩で組み立てられるものではありません。 5. 参考参考文献: ソースコード: https://github.com/vuejs/vue/blob/v2.6.10/src/core/instance/proxy.js 以下もご興味があるかもしれません:
|
<<: XHTMLはHTMLのいくつかの廃止された要素を使用しなくなりました
>>: MySQL で最大接続数を正しく変更する 3 つの方法
HTML を使用して動的な Web クロックを作成します。コードは次のとおりです。 <!DOC...
移動を実現するためにtranslateパラメータを使用しますtranslateX: X 軸に沿って移...
目次なぜパーティションが必要なのでしょうか?パーティショニング戦略パーティションの危険性なぜパーティ...
Dockerで作成したコンテナを削除する方法1. まず、docker -s -aコマンドを使用してす...
ビュー:一時テーブルを繰り返し使用する場合、将来の使用を容易にするために別名を付けることができます。...
検証環境: [root@~~/]# rpm -qa | grep mysql mysql-5.6.2...
/etc/my.confファイルで、[mysqld]の下に次の行を追加します: skip-grant...
この記事では、JavaScriptにおけるアロー関数と通常の関数の違いについて解説します。具体的な内...
参考までに、シンプルなナンバープレート入力コンポーネント(vue)です。具体的な内容は次のとおりです...
この記事では、参考までにMySQL 8.0.15のインストールと設定のグラフィックチュートリアルを紹...
Jupyter ノートブックは、主に Python コードの記述、より具体的にはディープラーニング開...
序文MySQL データのインポートとエクスポートは mysqldump コマンドで解決できることは誰...
1. 問題の紹介ユーザー テーブルに 3 つのフィールドが含まれているシナリオを想定します。 id、...
序文私は、Web サイトのフロントエンド パフォーマンス最適化のための JavaScript と C...
この記事の例では、WeChatアプレットの検索ボックス機能を実装するための具体的なコードを参考までに...