中文字幕精品亚洲无线码二区,国产黄a三级三级三级看三级,亚洲七七久久桃花影院,丰满少妇被猛烈进入,国产小视频在线观看网站

JavaScript 沙箱

標題圖

概述

沙箱可(ke)以簡單的(de)(de)理(li)解為一個虛擬機(ji),是一個和宿(su)主(zhu)機(ji)隔離(li)的(de)(de)環(huan)境,在這個環(huan)境中去(qu)運行(xing)一些不(bu)受信任的(de)(de)代碼(ma)或者應用程序,防止(zhi)不(bu)安(an)全(quan)的(de)(de)代碼(ma)對(dui)系統造成(cheng)損害(hai)。

比(bi)如我(wo)們(men)現在知道某個(ge)(ge)應用是(shi)詐騙(pian)軟件(jian)或(huo)者病毒軟件(jian),但是(shi)我(wo)們(men)依舊(jiu)想要(yao)運行,想逆(ni)向分析(xi)他,那么我(wo)們(men)就可以選擇在電(dian)腦上安裝一個(ge)(ge)虛(xu)擬(ni)機,在這個(ge)(ge)虛(xu)擬(ni)機中,我(wo)們(men)將對(dui)攝(she)像(xiang)頭的訪(fang)問(wen)引導至一張靜態圖片或(huo)者視頻,將麥克(ke)風的訪(fang)問(wen)引導至一個(ge)(ge)事先錄制好(hao)的音頻文件(jian)中,通訊(xun)錄、應用列表(biao)我(wo)們(men)也(ye)提(ti)前(qian)做好(hao)“偽(wei)裝”提(ti)供給這個(ge)(ge)軟件(jian)。

上(shang)面(mian)所(suo)述的整個過程實際就是(shi)建立沙(sha)箱的一個過程,運行在這里面(mian)的應用所(suo)能訪(fang)問到的都是(shi)我們事先準備好的,他(ta)無法直(zhi)接訪(fang)問到我們的電腦環(huan)境,從而(er)保證了我們不受到惡(e)意攻擊。

計算機領域版的楚門的世界

當然(ran),電影也很好看(kan),推薦大家(jia)看(kan)看(kan)~

沙(sha)箱(xiang)機(ji)(ji)制的原理(li)非常好理(li)解(jie),適用性也很廣,在(zai)計算(suan)機(ji)(ji)領域中,沙(sha)箱(xiang)也存在(zai)很多種(zhong),本文(wen)僅介紹 JavaScript 中的沙(sha)箱(xiang)實(shi)現。

格局打開,不要僅僅把目光放在計算機領域,沙箱本質上就是 **讓你看到我想讓你看到的東西 **,詐騙實際也是(shi)遵循這種,很刑的。

應用場景

沙箱的應用場景十分(fen)廣泛,包(bao)括操作系統、網(wang)絡瀏覽器、移動應用程序等。

本文要介(jie)紹(shao)的 JS 沙箱通常(chang)(chang)是(shi)(shi)用(yong)于 Web 瀏覽器中的,限(xian)制(zhi)不受(shou)信(xin)任的代碼的訪(fang)問權限(xian),通常(chang)(chang)認為用(yong)戶自己編寫的代碼就(jiu)是(shi)(shi)不受(shou)信(xin)任的代碼。

服(fu)務器端也是可以使用 js 沙箱的(de)(de)(de)(de),用以執行不受信任的(de)(de)(de)(de)代碼(ma),比如在 leetcode 上做題的(de)(de)(de)(de)時(shi)候(hou),我(wo)們(men)提交的(de)(de)(de)(de)代碼(ma)是在服(fu)務器端執行的(de)(de)(de)(de),這是為了(le)防止用戶寫一些(xie)惡意的(de)(de)(de)(de)代碼(ma)突破權限,對服(fu)務器造成危害。

所以(yi),JS 沙箱的應用主要圍繞(rao)以(yi)下兩點:

  1. 安全:解析不受信的 js 文件,防止 XSS 等
  2. 應用程序隔離:限制代碼訪問相關的對象,如彈窗廣告

詳細(xi)展開可以(yi)有更多,但是(shi)大(da)體方向是(shi)這兩個。

實現

實現的思路上,可以(yi)大(da)(da)致(zhi)劃分(fen)為三大(da)(da)類:IFrame、JavaScript 語言特性、快照(zhao)

IFrame

特點 :瀏覽器(qi)支持的 HTML 元素,自(zi)帶沙(sha)箱隔離,能夠與主頁面通信。

缺點 :瀏覽器會為其單獨開啟一(yi)個子(zi)進程,有額外(wai)的(de)性能開銷(xiao)。不同瀏覽器對 sandbox 屬性的(de)支(zhi)持也有所不同

HTML元素,這個實際是瀏覽器支持的一種,實現會比較簡單,我們只需要使用對應的屬性 sandbox 即可,主要關注 allow-scripts 屬性, [1], 不過就個人使用情況而言,在使用 iframe 的時候,這個屬性(xing)基本都(dou)處于開(kai)啟狀態,不開(kai)啟的話,在嵌(qian)入一些(xie)網站的時候可能會顯示異常。

<iframe src="//bing.com" sandbox="allow-scripts" />

如上就是一個比較簡單的實現,我們禁用(yong)了(le)其他的能力,僅啟(qi)用(yong)了(le)腳(jiao)本執行的能力。

allow-scripts 僅允許執行腳本,但(dan)是無法創建(jian)彈窗(chuang)這類窗(chuang)口。

不過尤其注意,作為一種安(an)全(quan)機制,沙(sha)箱(xiang)(xiang)并不能保障絕(jue)對的安(an)全(quan),所(suo)以對于沙(sha)箱(xiang)(xiang)中(zhong)的內容(rong),我們還是需(xu)要(yao)保證加載(zai)的內容(rong)的可信度和安(an)全(quan)性,避免惡(e)意用戶突破(po)或繞過沙(sha)箱(xiang)(xiang)造(zao)成(cheng)攻擊,導致我們產生損失。

主要是存在跨站(zhan)腳本攻擊(XSS)的問題(ti),這里舉兩個(ge)例(li)子:

  1. 竊取敏感信息:如登錄憑據,通過過濾相關標簽或者編碼來規避。
  2. 點擊劫持:釣魚網站,通常不是對網站的危害,而是對用戶的,采用禁止網站被嵌入(X-Frame-OptionsContent-Security-Policy)來規避

一般來說(shuo),我(wo)們在 iframe 中都會訪問受信的(de)站(zhan)點(dian)(dian),即使是(shi)彈(dan)窗廣告(gao),不(bu)過對于(yu)廣告(gao),我(wo)們通常會限(xian)制一些操作,比如(ru)不(bu)允(yun)許運行腳本。如(ru)果不(bu)加以限(xian)制,他(ta)可能(neng)不(bu)會直接危害到我(wo)們的(de)站(zhan)點(dian)(dian)安全,但是(shi)可能(neng)有用(yong)戶(hu)信任下(xia)降及(ji)影響(xiang)品牌聲譽的(de)問題(ti),當有更好的(de)站(zhan)點(dian)(dian)作為替(ti)代的(de)時(shi)候,那用(yong)戶(hu)則會棄之如(ru)敝履。

目前這種彈窗廣告你(ni)已(yi)經(jing)很少能在正規的網站上看到了(le),各個(ge)大廠更傾向于在信息(xi)流中加入廣告。

JavaScript 語言特性

特點:各個瀏覽器表現基本(ben)一致

缺點:性能表現與代碼實現的優(you)劣相關

前文說過,沙箱本質(zhi)是(shi)一種安全機制,是(shi)為了_** 限制第三方不受信(xin)任的代碼對系統內容的訪問(wen) **_,所以結合我(wo)(wo)們(men)對 JavaScript 語言的了解,我(wo)(wo)們(men)可(ke)以考(kao)慮(lv)作用域來(lai)限制訪問(wen)系統級(ji)變(bian)量。

作用域

目前市面上的編程語言,基本都有作用域的概念:在程序中定義變量的可見性和訪問范圍。 它直接決(jue)定了(le)變量(liang)的生(sheng)命周期和可以訪問變量(liang)的代碼片段,一般作用域(yu)[2]包括:

  1. 全局作用域(Global Scope):當前程序可以在任意位置處訪問的變量或函數,如 window。
  2. 模塊作用域(Module Scope):即 import 和 export,通常認為一個文件是一個模塊,在文件內定義的變量或函數都是該模塊私有的,如需在外部使用,則需要 export。
  3. 函數作用域(Function Scope):由函數創建的作用域,在 JavaScript 中,創建函數會為我們創建一個獨立的作用域,在 es6 之前沒有 es Module 規范時,我們使用 Function 幫助我們創建獨立的作用域來實現模塊化,即 umd 和 amd。
  4. 塊級作用域(Block Scope):es6 中引入,用一對花括號括起來的代碼塊,只對 let 和 const 聲明有效。var 聲明無效。

看到這(zhe)里,不(bu)難看出,作用(yong)域(yu)實(shi)(shi)際就(jiu)是一(yi)個(ge)天然(ran)的沙盒,我們可(ke)以這(zhe)樣實(shi)(shi)現:

window; // 瀏覽器的 window 對象
window.app = 2; // 增加一個 app 字段,并將其賦值為 2

function execCode(code: string) {
  const window = null;
  ;
}

const code = 'window.app = 1';
execCode(code); // 將 window.app 的值修改為 1,執行結果:Uncaught TypeError: Cannot set properties of null (setting 'app')

可(ke)以(yi)看到,此(ci)時執(zhi)行第三方代(dai)碼的時候,這些代(dai)碼是無法(fa)訪問我們的 window 對象(xiang)的,從而保(bao)證了我們的 window 對象(xiang)的安全。

但實際這并不是真正的安全,我們依舊有辦法能夠繞過他,比如,當我們全局定義了一個函數 updateApp(app) 的時候,我們(men)在這里實際可以通過調用這個函數(shu)的方(fang)式來繞過我們(men)作用域(yu)的限制:

function updateApp(app: number) {
  window.app = app;
}

execCode('updateApp(1)'); // 執行成功,window.app 此時為 1

所以我們又要重申一遍:作為一種安全機制,沙箱并不能保障絕對的安全

這里沒(mei)有考慮 with 關鍵字,因為(wei)他已(yi)(yi)經(jing)從 es5 開始的嚴格(ge)模式下就已(yi)(yi)經(jing)被禁用了,而現在由于我們使(shi)用的框(kuang)架默認是(shi)以嚴格(ge)模式執行的,所以可(ke)以說 with 關鍵字其實已(yi)(yi)經(jing)處于不(bu)(bu)可(ke)用的狀(zhuang)態了。新項目(mu)已(yi)(yi)經(jing)不(bu)(bu)建議使(shi)用,但是(shi)老項目(mu)還在用的話,那就保持現狀(zhuang)吧。

不過對于這種方式實現的沙盒,我們實際可以進一步優化,引入 JavaScript 中的 new Function [3] 構造函數來執行代碼,避免一些簡單的安全(quan)問題:

function execCode(code) {
  const func = new Function('window', code);
  func(null);
}

此時再執行時,你會發現,updateApp(1) 執行會報錯 ReferenceError: updateApp is not defined ,代碼字符(fu)串編(bian)譯后(hou)無法訪問我們的(de) updateApp 函數了。

因為我們在這里構造了一個類似于 function (window) { window.app = 1 } 的函數,并(bing)在后續執行調用動作(zuo)。

eval 能夠(gou)訪(fang)問本地作(zuo)用域(yu),new Function 則只能訪(fang)問全局(ju)變量和自己的(de)局(ju)部變量,同時(shi)其構造器創建時(shi)所在的(de)作(zuo)用域(yu)的(de)內容(rong)是(shi)無法(fa)訪(fang)問的(de)。

Proxy 代理

看上去,Proxy 是(shi)一(yi)個(ge)比(bi)較復雜(za)的內容,但實(shi)際上他本質上就(jiu)是(shi)一(yi)個(ge)攔(lan)截器,在(zai)訪問(wen)目標內容之(zhi)前(qian),需要先經過 Proxy 幫忙去通知。

一(yi)個更貼近現(xian)實的例子,Proxy = 租(zu)房中介,你(ni)想要(yao)租(zu)房,就需要(yao)通過中介去介紹。

如果你繞(rao)過中介直接和房東交易(yi),當然也是(shi)可(ke)行(xing)的,因為原始的交易(yi)對象是(shi)你已知的。

Proxy 的(de)一個簡單示例:

const windowProxy = new Proxy(window, {
  get(obj, propKey) {
    if (propKey === 'test') {
      return 'hello world';
    }
    return obj[propKey];
  }
})

windowProxy.test; // hello world,通過中介交易
window.test; // undefined,繞過中介直接和房東交易

通過上面這個簡單的例子,我們可以很輕松的看出,我們在創建出來的 Proxy 對象中限制了他訪問 test 屬性(xing)的(de)內容,這實際(ji)上是在(zai)做我們一(yi)開始(shi)說的(de),偽裝應用(yong)程(cheng)序(xu)所(suo)需要的(de)內容(變量等),提(ti)供(gong)給應用(yong)程(cheng)序(xu)使用(yong),從而實現(xian)對惡意(yi)攻擊的(de)防范。至于(yu)運行(xing)代碼(ma)?那不好意(yi)思,Proxy 本身是無法(fa)像(xiang) eval 和 new Function 一(yi)樣去運行(xing)一(yi)段代碼(ma)的(de)。

不過 Proxy 方式(shi)創(chuang)建沙(sha)箱也(ye)需要注意:

  1. proxy 默認只會代理一級對象:也就是說,當訪問的對象是 { a: { b: { c: 1 } } }這種,用戶訪問 proxy.a.b.c其實操作的就是原對象。

基于快照的沙箱

快照(Snapshot),就是(shi)存(cun)儲某(mou)一時刻相關(guan)數(shu)據的副本。

基于快照的(de)沙(sha)箱(xiang),顧名(ming)思義(yi),就是在程序運(yun)行(xing)的(de)某一(yi)個(ge)時(shi)刻,或者(zhe)執行(xing)某一(yi)個(ge)操作時(shi)保存(cun)當(dang)前運(yun)行(xing)環境(jing)(jing)副(fu)本,再后續的(de)某一(yi)個(ge)時(shi)刻恢復原運(yun)行(xing)環境(jing)(jing),從而(er)實現沙(sha)箱(xiang)機制。

通(tong)常我(wo)們是(shi)將副本用于(yu)操(cao)作,操(cao)作結束時(shi),將副本的更新寫入原始運行環(huan)境,舉個例(li)子(zi):

const snapshotSandbox = {
  original: null,
  copied: null,
  beforeAction: (obj, dangerKeys) => {
    // 保留原始副本
    this.original = obj;
    const snapshot = {};
    // 記錄當前信息,做一次快照
    for (const key of Object.keys(obj)) {
      if (dangerKeys.includes(key)) {
        // 對于敏感信息,不提供或提供加密信息
        continue;
      }
      snapshot[key] = obj[key];
    }
    console.log(snapshot);
    this.copied = snapshot;
    return this.copied;
  },
  afterAction: () => {
    // 將操作結果更新到原始副本中
    for (const key of Object.keys(this.copied)) {
      this.original[key] = this.copied[key];
    }
  }
}
 

function getUserId(user) {
  const id = user.id;
  const name = user.name;
  console.log('id', id, 'name', name); 
  // ajax('用于第三方不安全平臺登記認證');
}
const code = getUserId.toString();

const base = {
  id: 'xxxx',
  name: '一個人',
  age: '12',
  phoneNo: '1333333333333'
};

// 1. 現在假設有一個危險操作被注入到頁面上會使用用戶的 ID 信息(身份證)
const userInfo = snapshotSandbox.beforeAction(base, ['id', 'phoneNo']);
// 2. 做壞事
;
// 3. 把更新的內容寫回原來的對象
snapshotSandbox.afterAction();
console.log('使用的 userInfo 信息', userInfo);
console.log('最終操作后的 userInfo 信息', base);
console.log('這兩個信息理論上不是同一個對象', userInfo !== base)

這個(ge)實現(xian)僅(jin)僅(jin)是(shi)其中一(yi)種方(fang)式,在微前(qian)端中,基于快照(zhao)的(de)實現(xian)在以前(qian)也是(shi)一(yi)種流行的(de)版本,目的(de)是(shi)為了(le)隔離(li)不同子應用,現(xian)在多數基于 Proxy 來實現(xian)了(le),但快照(zhao)沙箱依舊是(shi)作(zuo)為一(yi)種降級方(fang)案(an)去兼容老舊的(de)瀏覽器。

最后

我們從應用場景的角度分析,JS 沙箱聚焦于 “安全防護” 與 “應用隔離” 這兩大核心需求:
在 Web 瀏覽器端,JS 沙箱能夠限制用戶自行編寫的代碼作用范圍。例如,它可實現攔截彈窗廣告、抵御 XSS 攻擊等功能,避免不可信的 JS 文件對頁面正常運行造成干擾。而在服務器端,如 LeetCode 代碼提交、在線編輯器等,沙箱可以提供有力保障。它能夠防止用戶提交的惡意代碼突破權限限制,從而避免服務器配置被篡改以及數據被竊取的風險。
盡管(guan) Web 瀏覽器(qi)(qi)端(duan)(duan)和服務器(qi)(qi)端(duan)(duan)的部署(shu)環境存在(zai)差(cha)異,然而它(ta)們的最終目標是一致的:即,確保代(dai)碼在(zai)可控范圍內(nei)運行,降(jiang)低風(feng)險擴散的可能性。

參考文章

[1]:

[2]:

[3]:

posted @ 2025-09-25 13:55  Achieve前端實驗室  閱讀(101)  評論(0)    收藏  舉報