curl 慢 不稳定_Node.js VM 不完全指北
前言
vm 是 Node.js 頂級模塊之一,你可以直接在 Node.js 中使用 require 引入,vm 的功能是可以在 V8 虛擬機的上下文中編譯和執行 JavaScript 代碼。
The vm module enables compiling and running code within V8 Virtual Machine contexts. ——來自Node.js文檔它比 eval、Function 更安全,而且同樣很簡單。
入門
那么我們可以用它來做什么呢?假設你有一段可執行的js代碼,最簡單的兩種方法讓它run起來:
這兩種都是手動、主動的執行。如果想把這個過程自動化,把目標代碼放入到我的程序里呢?方法也有:
下面是 eval 和 Function 實現 runtime 的語法最基本實現,vm 我們會在后面詳細介紹:
// eval(string)console.log(eval('2 + 2')); // expected output: 4console.log(eval(new String('2 + 2'))); // expected output: 2 + 2 const sum = new Function('a', 'b', 'return a + b');console.log(sum(2, 6)); // expected output: 8我們可以用它們實現一個 javascript 的 runtime 來執行目標代碼。比如這樣一個場景,我的產品是一個 SDK Playground,我的客戶是開發者,它寫了一段測試代碼想放進我提供的產品里看看運行結果如何,我想要做成一個自動化的服務,那么用上面語法寫這樣的 JS runtime 是一個不錯的選擇。
上面提到了 eval、Function,他們語法和功能我們這里不做介紹了,他也能執行目標代碼,但是卻帶來一些問題:首先最大的是安全性,無論如何目標代碼不能影響我正常的服務,也就是說,這個執行環節得是一個沙盒環境,而eval顯然并不具備這個能力。如果需要一段不信任的代碼放任它執行,那么不光服務,整個服務器的文件系統、數據庫都暴露了。甚至目標代碼會修改eval函數原型,埋入陷阱等等。
eval 的安全性問題我們就不做更多解釋了,其實在生產中,我們應該盡量避免使用它(甚至很多lint規則發現它存在都會報錯)。總結來說,作為js的一個全局對象,它并沒有任何沙盒的設計,這顯然是無法在生產中使用的。而 Funtion 也有同樣的安全問題,他們倆的差異可以查閱 MDN 文檔,這里按下不表。
進階
那么,既然說到了沙盒屬性,vm具備怎么的特性呢?
首先你可以使用vm.Script方法構建一個腳本對象:new vm.Script(code[, options]),他的API可以總結為下面三個:
- script.runInThisContext(opts) - 在當前作用域中運行腳本,也就是說,腳本可以訪問當前腳本的全局變量,而不是局部作用域。
- script.runInContext(context, opts) - 在提供的作用域中運行腳本,作用域是某個 vm.createContext 的結果。 在 script.runInContext 中,您可以提供一個自定義可控sandbox。
- script.runInNewContext(sandbox, opts) - 在一個新的 sandbox 的作用域范圍內運行腳本。即 runInNewContext 會為您自動調用 vm.createContext。
當然也可以直接用vm上的方法:
const vm = require('vm'); vm.runInThisContext(code, opts); vm.runInNewContext(code, sandbox, opts); vm.runInContext(code, context, opts);從上面可以看出,vm始終提供了一個可選的作用域來實現沙盒特性,以此來隔絕沙盒內外的影響。 更多 API 細節查看官網文檔:https://nodejs.org/api/vm.html#vm_vm_executing_javascript
性能對比
比起其他實現runtime的方案,vm的速度會慢一些,因為他建立了封閉而完整的上下文環境。下面來個小實驗:
var code = ` var fn = () => {} I = 100; while(I--) { fn(); } `;const vm = require('vm'); const context = vm.createContext(); const script = new vm.Script(code);console.time('vm'); script.runInContext(context); console.timeEnd('vm');console.time('eval'); eval(code); console.timeEnd('eval');// Results: vm: 1.122ms eval: 0.156ms可以明顯看出,vm比eval還是慢了不少。
安全性
使用vm的模塊會比eval更為安全,因為vm模塊運行的腳本完全無權訪問外部作用域(或自行設置一個有限的作用域)。 腳本仍在同一進程中運行,因此為了獲得最佳安全性。當然你可以給上下文傳入一些通用的API方便開發:
vm.runInNewContext(`const util = require(‘util’);console.log(util); `, {require: require,console: console });此外,另一個開源庫vm2針對vm的安全性等方面做了更多的提升,vm2。避免了一些運行腳本有可能“逃出”沙盒運行的邊緣情況,語法也跟易于上手,很推薦使用。
實戰 Demo(我能用它來干什么?)
前短時間我用 VM + Midway 做了一個自用的 FaaS 服務,跟其他大型 FaaS 服務基本功能一樣,你可以在上面運行、開發和管理你的 serverless 函數,而無需考慮構建和部署基礎框架,也不用寫任何框架相關的代碼,只專注于業務。項目地址:lqs469/micro-serverless: A micro serverless service based on Node.js VM
搭建一些簡單的個人助理服務,例如天氣提示,新聞推送或單純提醒我不要錯過比賽直播。 而這些小需求并沒有必要用完整的框架來搭建幾個復雜完整的應用程序來解決。 而 serverless 顯然很合適。 所以,我做了這個能滿足我需求且簡易,靈活的 serverless 服務。
做一個 Github Trending
async function main() {const url = 'https://github-trending-api.now.sh/repositories';const res = await ctx.curl('https://github-trending-api.now.sh/repositories',{ dataType: 'json' },);return res.data.map(item => ({title: `${item.name} | ? ${item.author} | ??${item.stars} | ${item.language}`,url: item.url,desc: item.description,})); }GET //127.0.0.1:7001/vm/github_trending
根據傳入的地理位置查詢天氣
你可以給函數加入參數,方法時通過請求 URL 的 query,然后在函數中通過 ctx.query 取到。比下面的例子可以請求://127.0.0.1:7001/vm/weather?location=Tokyo。
// weather.js async function main() {const { location = 'New York’ } = ctx.query;const url = `http://api.weatherstack.com/current?access_key=95f5ee664befefc1c49fa0dac0da19c7&query=${location}`;const res = await ctx.curl(url, { dataType: ‘json’ });return res.data; }GET //127.0.0.1:7001/vm/weather?location=Tokyo
具體實現細節和函數規則可以看Readme。
總結
Vm 是一個很有用的 API,但是在生產中運用卻很少,原因其實也很明顯——安全性,沒有人愿意開著飛機時引擎暴露給別人,下面總結一下 vm: - 足夠實現一些 runtime 場景,讓你可以開著飛機修飛機。 - 避免了使用極度不安全的 eval 或者 Function 。 - Vm 模塊似乎提供了比較安全的實現,以及精心設計的沙盒模型,但是攻擊者仍然可以利用它(是的,有興趣的同學可以查看這篇文章。 - Vm2 似乎提供了一個更堅固的沙箱,代碼無法“逃脫”,但是安全性問題也可能潛伏其中。
總而言之,我仍然認為運行第三方代碼的唯一安全方法是“物理地”將應用程序與該代碼分離,例如,通過虛擬機、docker、容器中運行它才是讓你更放心的方案,至少在生產中采用絕對安全的方案可以讓你睡個好覺。但是如果是對于安全要求沒有那么高的場景(比如上面的個人服務),vm 不失為一個簡單有效的 runtime 方案,基于此可以設計出很多有趣的東西。
總結
以上是生活随笔為你收集整理的curl 慢 不稳定_Node.js VM 不完全指北的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 工银压岁金是什么存款
- 下一篇: labview如何加载库_迈德威视工业相