国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

動手寫 js 沙箱

AndroidTraveler / 1447人閱讀

摘要:本文由云社區發表作者市面上現在流行兩種沙箱模式一種是使用還有一種是直接在頁面上使用進行執行。接下來我們來一步一步分析如果做到在前端的沙箱文末看俺有沒有心情放一個彩蛋吧。等價于所以第一步改寫上面的將里面變量的獲取途徑控制在自己的手里。

本文由云+社區發表

作者:ivweb villainthr

市面上現在流行兩種沙箱模式,一種是使用iframe,還有一種是直接在頁面上使用new Function + eval進行執行。 殊途同歸,主要還是防止一些Hacker們 吃飽了沒事干,收別人錢來 Hack 你的網站。 一般情況, 我們的代碼量有60%業務+40%安全. 剩下的就看天意了。接下來,我們來一步一步分析,如果做到在前端的沙箱.文末 看俺有沒有心情放一個彩蛋吧。

直接嵌套

這種方式說起來并不是什么特別好的點子,因為需要花費比較多的精力在安全性上.

eval執行

最簡單的方式,就是使用eval進行代碼的執行 eval("console.log("a simple script");");

但,如果你是直接這么使用的話, congraduations... do die... 因為,eval 的特性是如果當前域里面沒有,則會向上遍歷.一直到最頂層的global scope 比如window.以及,他還可以訪問closure內的變量.看demo:

function Auth(username)
{
  var password = "trustno1";
  this.eval = function(name) { return eval(name) } // 相當于直接this.name
}

auth = new Auth("Mulder")
console.log(auth.eval("username")); // will print "Mulder"
console.log(auth.eval("password")); // will print "trustno1"

那有沒有什么辦法可以解決eval這個特性呢? 答: 沒有. 除非你不用 ok,那我就不用. 我們這里就可以使用new Function(..args,bodyStr) 來代替eval。

new Function

new Function就是用來,放回一個function obj的. 用法參考:new Function. 所以,上面的代碼,放在new Function中,可以寫為: new Function("console.log("a simple script");")();

這樣做在安全性上和eval沒有多大的差別,不過,他不能訪問closure的變量,即通過this來調用,而且他的性能比eval要好很多. 那有沒有辦法解決global var的辦法呢? 有啊... 只是有點復雜先用with,在用Proxy

with

with這個特性,也算是一個比較雞肋的,他和eval并列為js兩大SB特性. 不說無用, bug還多,安全性就沒誰了... 但是, with的套路總是有人喜歡的.在這里,我們就需要使用到他的特性.因為,在with的scope里面,所有的變量都會先從with定義的Obj上查找一遍。

 var a = {
    c:1
}
var c =2;
with(a){
    console.log(c); //等價于c.a
}

所以,第一步改寫上面的new Function(),將里面變量的獲取途徑控制在自己的手里。

 function compileCode (src) {  
  src = "with (sandbox) {" + src + "}"
  return new Function("sandbox", src)
}

這樣,所有的內容多會從sandbox這個str上面獲取,但是找不到的var則又會向上進行搜索. 為了解決這個問題,則需要使用: proxy

proxy

es6 提供的Proxy特性,說起來也是蠻牛逼的. 可以將獲取對象上的所有方式改寫.具體用法可以參考: 超好用的proxy. 這里,我們只要將has給換掉即可. 有的就好,沒有的就返回undefined

function compileCode (src) {
  src = "with (sandbox) {" + src + "}"
  const code = new Function("sandbox", src)

  return function (sandbox) {
    const sandboxProxy = new Proxy(sandbox, {has})
    return code(sandboxProxy)
  }
}

// 相當于檢查 獲取的變量是否在里面 like: "in"
function has (target, key) {
  return true
}

compileCode("log(name)")(console);

這樣的話,就能完美的解決掉 向上查找變量的煩惱了。 另外一些,大神,發現在新的ECMA里面,有些方法是不會被with scope 影響的. 這里,主要是通過Symbol.unscopables 這個特性來檢測的.比如:

 Object.keys(Array.prototype[Symbol.unscopables]); 
// ["copyWithin", "entries", "fill", "find", "findIndex", 
//  "includes", "keys", "values"]

不過,經過本人測試發現也只有Array.prototype上面帶有這個屬性... 尷尬... 所以,一般而言,我們可以加上 Symbol.unscopables, 也可以不加。

 // 還是加一下吧
function compileCode (src) {  
  src = "with (sandbox) {" + src + "}"
  const code = new Function("sandbox", src)

  return function (sandbox) {
    const sandboxProxy = new Proxy(sandbox, {has, get})
    return code(sandboxProxy)
  }
}

function has (target, key) {  
  return true
}

function get (target, key) {  
// 這樣,訪問Array里面的 like, includes之類的方法,就可以保證安全... 算了,就當我沒說,真的沒啥用...
  if (key === Symbol.unscopables) return undefined
  return target[key]
}

現在,基本上就可以宣告你的代碼是99.999% 的5位安全數.(反正不是100%就行)

設置緩存

如果上代碼,每次編譯一次code時,都會實例一次Proxy, 這樣做會比較損性能. 所以,我們這里,可以使用closure來進行緩存。 上面生成proxy代碼,改寫為:

 function compileCode(src) {
    src = "with (sandbox) {" + src + "}"
    const code = new Function("sandbox", src)

    function has(target, key) {
        return true
    }

    function get(target, key) {
        if (key === Symbol.unscopables) return undefined
        return target[key]
    }

    return (function() {
        var _sandbox, sandboxProxy;
        return function(sandbox) {
            if (sandbox !== _sandbox) {
                _sandbox = sandbox;
                sandboxProxy = new Proxy(sandbox, { has, get })
            }
            return code(sandboxProxy)
        }
    })()
}

不過上面,這樣的緩存機制有個弊端,就是不能存儲多個proxy. 不過,你可以使用Array來解決,或者更好的使用Map. 這里,我們兩個都不用,用WeakMap來解決這個problem. WeakMap 主要的問題在于,他可以完美的實現,內部變量和外部的內容的統一. WeakMap最大的特點在于,他存儲的值是不會被垃圾回收機制關注的. 說白了, WeakMap引用變量的次數是不會算在引用垃圾回收機制里, 而且, 如果WeakMap存儲的值在外部被垃圾回收裝置回收了,WeakMap里面的值,也會被刪除--同步效果.所以,毫無意外, WeakMap是我們最好的一個tricky. 則,代碼可以寫為:

const sandboxProxies = new WeakMap()
function compileCode(src) {
    src = "with (sandbox) {" + src + "}"
    const code = new Function("sandbox", src)

    function has(target, key) {
        return true
    }

    function get(target, key) {
        if (key === Symbol.unscopables) return undefined
        return target[key]
    }
    return function(sandbox) {
        if (!sandboxProxies.has(sandbox)) {
            const sandboxProxy = new Proxy(sandbox, { has, get })
            sandboxProxies.set(sandbox, sandboxProxy)
        }
        return code(sandboxProxies.get(sandbox))
    }
}

差不多了, 如果不嫌寫的丑,可以直接拿去用.(如果出事,純屬巧合,本人概不負責).

接著,我們來看一下,如果使用iframe,來實現代碼的編譯. 這里,Jsfiddle就是使用這種辦法.

iframe 嵌套

最簡單的方式就是,使用sandbox屬性. 該屬性可以說是真正的沙盒... 把sandbox加載iframe里面,那么,你這個iframe基本上就是個標簽而已... 而且支持性也挺棒的,比如IE10.

這樣已添加,那么下面的事,你都不可以做了:

1. script腳本不能執行
2. 不能發送ajax請求
3. 不能使用本地存儲,即localStorage,cookie等
4. 不能創建新的彈窗和window, 比如window.open or target="_blank"
5. 不能發送表單
6. 不能加載額外插件比如flash等
7. 不能執行自動播放的tricky. 比如: autofocused, autoplay

看到這里,我也是醉了。 好好的一個iframe,你這樣是不是有點過分了。 不過,你可以放寬一點權限。在sandbox里面進行一些簡單設置

常用的配置項有:

配置 效果
allow-forms 允許進行提交表單
allow-scripts 運行執行腳本
allow-same-origin 允許同域請求,比如ajax,storage
allow-top-navigation 允許iframe能夠主導window.top進行頁面跳轉
allow-popups 允許iframe中彈出新窗口,比如,window.open,target="_blank"
allow-pointer-lock 在iframe中可以鎖定鼠標,主要和鼠標鎖定有關

可以通過在sandbox里,添加允許進行的權限.

這樣,就可以保證js腳本的執行,但是禁止iframe里的javascript執行top.location = self.location。 更多詳細的內容,請參考: please call me HR.

接下來,我們來具體講解,如果使用iframe來code evaluation. 里面的原理,還是用到了eval.

iframe 腳本執行

上面說到,我們需要使用eval進行方法的執行,所以,需要在iframe上面添加上, allow-scripts的屬性.(當然,你也可以使用new Function, 這個隨你...) 這里的框架是使用postMessage+eval. 一個用來通信,一個用來執行. 先看代碼:




 
   Evalbox"s Frame
   
 

這里順便插播一下關于postMessage的相關知識點.

postMessage 講解

postMessage主要做的事情有三個:

1.頁面和其打開的新窗口的數據傳遞

2.多窗口之間消息傳遞

3.頁面與嵌套的iframe消息傳遞

具體的格式為: otherWindow.postMessage(message, targetOrigin, [transfer]);

message是傳遞的信息,targetOrigin指定的窗口內容,transfer取值為Boolean 表示是否可以用來對obj進行序列化,相當于JSON.stringify, 不過一般情況下傳obj時,會自己先使用JSON進行seq一遍. 具體說一下targetOrigin. targetOrigin的寫入格式一般為URI,即, protocol+host. 另外,也可以寫為*. 用來表示 傳到任意的標簽頁中. 另外,就是接受端的參數.接受傳遞的信息,一般是使用window監聽message事件.

window.addEventListener("message", receiveMessage, false);

function receiveMessage(event)
{
  var origin = event.origin || event.originalEvent.origin; // For Chrome, the origin property is in the event.originalEvent object.
  if (origin !== "http://example.org:8080")
    return;

  // ...
}

event里面,會帶上3個參數:

data: 傳遞過來的數據. e.data

origin: 發送信息的URL, 比如: https://example.org

source: 發送信息的源頁面的window對象. 我們實際上只能從上面獲取信息.

該API常常用在window和iframe的信息交流當中. 現在,我們回到上面的內容.




 
   Evalbox"s Frame
   
 

iframe里面,已經做好文檔的監聽,然后,我們現在需要進行內容的發送.直接在index.html寫入:

// html部分


// 設置基本的安全特性


// js部分
function evaluate() {
  var frame = document.getElementById("sandboxed");
  var code = document.getElementById("code").value;
  frame.contentWindow.postMessage(code, "/"); // 只想同源的標簽頁發送
}

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

// 同時設置接受部分
window.addEventListener("message",
    function (e) {
      var frame = document.getElementById("sandboxed");
      // 進行信息來源的驗證
      if (e.origin === "null" && e.source === frame.contentWindow)
        alert("Result: " + e.data);
    });

實際demo可以參考:H5 ROCK

常用的兩種沙箱模式這里差不多講解完了. 開頭說了文末有個彩蛋,這個彩蛋就是使用nodeJS來做一下沙箱. 比如像 牛客網的代碼驗證,就是放在后端去做代碼的沙箱驗證.

彩蛋--nodeJS沙箱

使用nodeJS的沙箱很簡單,就是使用nodeJS提供的VM Module即可. 直接看代碼吧:

 const vm = require("vm");
const sandbox = { a: 1, b: 1 };
const script= new vm.Script("a + b");
const context = new vm.createContext(sandbox);
script.runInContext(context);

在vm構建出來的sandbox里面,沒有任何可以訪問的全局變量.除了基本的syntax.

原文鏈接:http://www.ivweb.io/topic/58d...

此文已由騰訊云+社區在各渠道發布

獲取更多新鮮技術干貨,可以關注我們騰訊云技術社區-云加社區官方號及知乎機構號

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/108998.html

相關文章

  • 動手 js 沙箱

    摘要:本文由云社區發表作者市面上現在流行兩種沙箱模式一種是使用還有一種是直接在頁面上使用進行執行。接下來我們來一步一步分析如果做到在前端的沙箱文末看俺有沒有心情放一個彩蛋吧。等價于所以第一步改寫上面的將里面變量的獲取途徑控制在自己的手里。 本文由云+社區發表作者:ivweb villainthr 市面上現在流行兩種沙箱模式,一種是使用iframe,還有一種是直接在頁面上使用new Func...

    endless_road 評論0 收藏0
  • 【mock service系列】Online mock service or API by Sand

    摘要:沙箱,第一反應,但并不是。為避免誤解,下文中所有提到都是指這個工具,不是沙箱。做什么的,根據其官網上的描述可以理解為快速生成,即時部署,協作構建并集成了調試工具。對個人而言,強烈推薦給入門的人。 Sandbox--沙箱,第一反應,但sorry并不是。 sandbox 這個詞大家并不陌生,但貌似國內的技術share中很少看到有提到這個工具的。為避免誤解,下文中所有提到sandbox都是指...

    zgbgx 評論0 收藏0
  • js沙箱內容

    摘要:好好的一個,你這樣是不是有點過分了。不過,你可以放寬一點權限。 摘至: please call me HR 市面上現在流行兩種沙箱模式,一種是使用iframe,還有一種是直接在頁面上使用new Function + eval進行執行. 殊途同歸,主要還是防止一些Hacker們 吃飽了沒事干,收別人錢來 Hack 你的網站. 一般情況, 我們的代碼量有60%業務+40%安全. 剩下的就看...

    Moxmi 評論0 收藏0
  • NPM酷庫:vm2,安全的沙箱環境

    摘要:而標準庫中的是不安全的,用戶腳本可以輕易突破沙箱環境,獲取主程序的上述代碼在執行時,程序在第二行就直接退出,虛擬機環境中的代碼逃逸,獲得了主線程的變量,并調用,造成主程序非正常退出。 NPM酷庫,每天兩分鐘,了解一個流行NPM庫。 今天我們要了解的庫是 vm2,則是一個Node.js 官方 vm 庫的替代品,主要解決了安全問題。 不安全的vm 在Node.js官方標準庫中有一個vm庫,...

    pkhope 評論0 收藏0
  • 為 Node.js 應用建立一個更安全的沙箱環境

    摘要:當運行函數的時候,只能訪問自己的本地變量和全局變量,不能訪問構造器被調用生成的上下文的作用域。如何建立一個更安全一些的沙箱通過上文的探究,我們并沒有找到一個完美的方案在建立安全的隔離的沙箱。 showImg(https://segmentfault.com/img/remote/1460000014575992); 有哪些動態執行腳本的場景? 在一些應用中,我們希望給用戶提供插入自定義...

    cartoon 評論0 收藏0

發表評論

0條評論

AndroidTraveler

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<