JavaScript >> Javascript 文檔 >  >> JavaScript

通緝:JavaScript 中的動態執行上下文

當今 Web 開發人員面臨的最常見問題之一是如何在不犧牲頁面安全性和穩定性的情況下將第三方 JavaScript 加載到頁面上。當然,它已經重複了足夠長的時間,大多數人都知道盲目地包含一個您沒有編寫的 JavaScript 文件是跨站點腳本 (XSS) 攻擊的必經之路,但是混搭的流行使我們多次重新解決了這個問題.可以肯定的是,我們需要一種安全的方式來將其他人的 JavaScript 加載到頁面上,並確保它不會對包含頁面產生負面影響。然而,還沒有人想出一種輕量級的方法來做到這一點。

當前解決方案

這對於網絡來說並不是一個新問題,因此已經有很多嘗試來解決這個問題。所有方法都涉及為 JavaScript 創建沙箱。目標是允許 JavaScript 在不訪問頁面所有部分的情況下執行。目前的一些方法:

  • **IFrames **- 此問題的經典解決方案是通過 iframe 從單獨的域將第三方 JavaScript 加載到頁面中。然後 iframe 成為 JavaScript 在其中執行而無法訪問父框架的沙箱(由於跨域限制)。
  • Facebook JavaScript (FBJS) – Facebook 為應用程序開發人員提供的 JavaScript 接口基本上由兩部分組成。第一個是腳本重寫,他們處理第三方 JavaScript 並修改函數和變量的名稱,以確保您的名稱不會與本機或主機對象重疊(這會產生安全問題)。第二步是鎖定 JavaScript 執行環境,以便您只能訪問 Facebook API 公開的對象。這是通過隱藏全局變量來完成的。這是一個安全隱患,因為瀏覽器會不斷添加新對象,但它可以完成工作。
  • 卡哈 – Google 嘗試為 JavaScript 建立對象能力安全模型。 Caja 通過重寫 JavaScript 使其在沙盒環境中執行來工作。然後,您可以決定將哪些對象公開給正在執行的代碼,以作為授予對某些功能的訪問權限的一種方式。生成的代碼相當鎖定,但更大且執行速度更慢。

所有這些方法都試圖完成完全相同的事情,即為一些 JavaScript 代碼提供一個經過淨化的環境來執行。不幸的是,每一個都會帶來額外的維護開銷和性能問題。

我們真正需要的東西

我們今天擁有的解決方案實際上是在嘗試創建一個新的執行上下文,其中某些對像不可用。執行上下文始終在 JavaScript 中創建和銷毀——例如,當您調用函數時。對於第三方而言,問題在於,當執行此腳本時,您不一定希望整個作用域鏈都在執行上下文中。這很困難,因為您通常不想要全局對象 (window ) 但您確實想要諸如 Object 之類的本機類型 , Array , String 等。您想要本地範圍,但不是全局和本地之間的所有內容。從範圍鏈中挑選櫻桃是不可能的,因此範圍鏈被中性化,只留下本地範圍,然後將對象向下傳遞到該範圍(FBJS 和 Caja 的方法)。

如果你想在你的 C++ 應用程序中嵌入 V8,Chrome 的 JavaScript 引擎,你可以通過創建一個基於全局對象的執行上下文,然後用它執行一些代碼(來自入門指南):

 // Create a stack-allocated handle scope.
HandleScope handle_scope;

// Create a new context.
Persistent<Context> context = Context::New();

// Enter the created context for compiling and
// running the hello world script.
Context::Scope context_scope(context);

// Create a string containing the JavaScript source code.
Handle<String> source = String::New("'Hello' + ', World!'");

// Compile the source code.
Handle<Script> script = Script::Compile(source);

// Run the script to get the result.
Handle<Value> result = script->Run();

// Dispose the persistent context.
context.Dispose(); 

在不剖析這段代碼的情況下,它基本上創建了一個新的執行上下文(通過 Context::New() ) 然後編譯並執行其中的 JavaScript。這就是你在 C++ 中的做法,這讓我想到了一個問題……為什麼我們不能在 JavaScript 中做類似的事情?以下是我的想法:

var context = new ExecutionContext(),
    result = context.eval("2 + 2");

所以在這裡,你創建一個新的 ExecutionContext object 代表一個全新的執行上下文,它有自己的全局對象和本機類型,但僅此而已。也許你可以在構造函數中指定一個全局對象:

var myglobal = {
        add: function(num1, num2){
            return num1 + num2;
        }
    },
    context = new ExecutionContext(myglobal),
    result = context.eval("add(2, 2)");

在這種情況下,myglobal 成為 context 中的全局對象 .所有本機類型構造函數最終都附加到 myglobal ,以及任何全局變量或函數。此外,myglobal 發布 add() 函數,因此它可以在 context 內部訪問 .當然還有 eval() 只是執行代碼。

這有什麼幫助?

想像一個旨在控制頁面上的一個元素的第三方腳本。您希望允許該腳本對元素進行某些訪問,但不希望它能夠與頁面的任何其他部分交互(這通常是您想要的廣告)。您可以通過以下方式專門為此目的設置執行上下文:

var element = new MyElementWrapper(document.getElementById("foo")),
    context = new ExecutionContext(),
    context.set("element", element),
    context.load("http://www.example.com/foo/bar.js");

假設 MyElementWrapper 是一個構造函數,它在 DOM 元素周圍創建一個包裝對象,這樣執行的代碼就無法訪問 DOM 樹的其餘部分。我使用 set() 定義一個名為 element 的新全局變量的方法 指向包裝器。然後通過load()下載並執行第三方腳本 在此上下文中,它可以訪問所有原生 JavaScript 類型,但不能訪問 DOM 或 BOM 全局變量。

這個解決方案並不完美,因為您必須知道腳本打算做什麼,這樣您才能提供正確的對象來完成執行。你也可能錯誤地傳入了一個執行上下文不應該訪問的對象。

這是現實的嗎?

我不知道這個想法到底有多可行——這只是我在嘗試思考 JavaScript 沙盒問題時突然想到的。從表面上看,考慮到底層的 JavaScript 引擎實現,這似乎很容易實現。我很想听聽那些在 JavaScript 引擎上工作的人關於這是否可以實現的反饋(當然,如果可以的話,你是否會選擇實現)。


Tutorial JavaScript 教程
  1. 在 PeerJs 正在進行的實時連接(流)期間請求視頻

  2. 缺失:在屬性 ID 之後

  3. 將 Vue/React 應用程序部署到 GH Pages

  4. 如何使用鼠標坐標在 React 中製作圖像按鈕。

  5. 如何自動重新加載我正在開發的 Chrome 擴展程序?

  6. 如何製作 Nuxt 全局對象?

  7. 雲計算的最佳語言是什麼?

  1. 在 JavaScript 中克隆數組

  2. 在新窗口中使用js打開多個水龍頭

  3. 反轉整數——正確的方法

  4. 適用於 JavaScript Azure 函數的 OpenAPI

  5. 使用按鈕的角度材料中的可擴展卡。

  6. 🛸 JavaScript 是傳值還是傳引用?讓我們來了解一下!

  7. 設計系統創建,從零開始到 npmjs.com - 第 1 部分

  1. 開始在 React Native 中構建移動應用程序需要了解的內容

  2. 編碼概念!圈複雜度

  3. 開爾文數據 API 入門

  4. 在 Firebase 上部署 nuxt