이번에는 Node.js어플리케이션용 샌드박스 환경 설정 방법을 가져왔습니다. Node.js 애플리케이션용 샌드박스 환경 설정 시 사용할 주의사항은 무엇입니까? 다음은 실제 사례입니다. 봐.
스크립트를 동적으로 실행하는 시나리오는 무엇입니까?
일부 응용 프로그램에서는 일부 게임의 lua 스크립트와 같은 Microsoft Office의 VBA와 사용자 정의 논리를 게시할 수 있는 FireFox의 "Grease Monkey Script"와 같은 사용자 정의 논리를 삽입할 수 있는 기능을 사용자에게 제공하고자 합니다. 당신의 상상력을 사용하여 당신이 통제할 수 있는 범위와 권한 내에서 재미 있고 유용한 일을 하여 사용자의 개인화된 요구 사항을 충족할 수 있는 능력을 확장하십시오. 대부분은 일부 온라인 시스템 및 제품에서 유사한 요구 사항을 갖는 클라이언트 프로그램입니다. 실제로 많은 온라인 응용 프로그램은 Google Docs Script의 앱과 같이 스크립트를 사용자 정의하는 기능도 제공하므로 정말 유용한 작업을 수행할 수 있습니다.JavaScript를 사용하는 작업(예: 문서 열기 이벤트 또는 셀 변경 이벤트에 대한 응답으로 코드 실행, 수식에 대한 사용자 정의 스프레드시트 기능 만들기 등)
"사용자 컴퓨터에서" 실행되는 클라이언트 응용 프로그램과 달리 사용자 정의 스크립트는 일반적으로 사용자 자신에게만 영향을 미칠 수 있습니다. 온라인 응용 프로그램이나 서비스의 경우 "보안", 사용자 정의 스크립트와 같은 일부 상황이 더 중요해집니다. "는 엄격하게 제한되고 격리되어야 합니다. 즉, 호스트 프로그램이나 다른 사용자에게 영향을 미칠 수 없습니다. Safeify는 신뢰할 수 없는 사용자 정의 스크립트를 안전하게 실행하는 데 사용되는 Nodejs 애플리케이션용 모듈입니다.동적 스크립트를 안전하게 실행하는 방법은 무엇입니까?
먼저 JavaScript 프로그램에서 코드 조각을 동적으로 실행하는 방법을 살펴보겠습니다. 예를 들어 유명한 evaleval('1+2')위의 코드는 문제 없이 원활하게 실행되었습니다. eval은 전역 개체의 함수 속성이며, 실행된 코드는 다른 코드와 동일한 속성을 갖습니다. 권한이 있으면 "실행 컨텍스트"의 로컬 변수와 모든 "전역 변수"에 액세스할 수 있습니다. 이 경우 매우 위험한 기능입니다. Functionn을 다시 살펴보겠습니다. Function 생성자를 통해 동적으로 함수를 생성하고 실행할 수 있습니다.
const sum = new Function('m', 'n', 'return m + n'); console.log(sum(1, 2));Function 생성자를 사용하여 생성된 함수는 컨텍스트를 생성하지 않습니다. 클로저는 전역 범위에서 생성됩니다. . 함수를 실행할 때 자신의 지역 변수와 전역 변수에만 액세스할 수 있으며 호출되는 Function 생성자에 의해 생성된 컨텍스트 범위에는 액세스할 수 없습니다. 마치 땅 위에 서 있는 사람과 얇은 종이 위에 서 있는 사람처럼, 이 장면에서는 상하의 구별이 거의 없다. ES6의 새로운 기능인 프록시와 결합하면 더 안전할 수 있습니다
function evalute(code,sandbox) { sandbox = sandbox || Object.create(null); const fn = new Function('sandbox', `with(sandbox){return ($[code])}`); const proxy = new Proxy(sandbox, { has(target, key) { // 让动态执行的代码认为属性已存在 return true; } }); return fn(proxy); } evalute('1+2') // 3 evalute('console.log(1)') // Cannot read property 'log' of undefined우리는 eval이든 함수이든 실행 중에 범위가 레이어별로 검색된다는 것을 알고 있습니다. 발견되지 않으면 전역으로 이동합니다. 따라서 Proxy의 원리를 사용하십시오. 즉, "anti-escape" 목적을 달성하기 위해 실행된 코드를 sandobx에서 찾을 수 있습니다. 브라우저에서는 iframe을 사용하여 재전송에 안전한 격리 환경을 만들 수도 있습니다. 이 글 역시 Node.js에 중점을 두고 있으므로 여기서는 이에 대해 너무 많이 논의하지 않겠습니다.
Node.js에 다른 옵션이 있나요?
const vm = require('vm'); const script = new vm.Script('m + n'); const sandbox = { m: 1, n: 2 }; const context = new vm.createContext(sandbox); script.runInContext(context);위 코드를 실행하여 결과를 얻습니다. 3. 동시에 vm.Script를 통해 코드 실행에 대한 "최대 밀리초"를 지정할 수도 있습니다. 지정된 시간이 실행을 초과하면 실행이 됩니다.
try { const script = new vm.Script('while(true){}',{ timeout: 50 }); .... } catch (err){ //打印超时的 log console.log(err.message); }위의 스크립트 실행은 실패합니다. 시간 초과가 감지되고 예외가 발생합니다. 그러나 다음의 시간 초과 옵션에 유의해야 합니다. vm.Script는 "동기 생성에만 유효"하며 포함하지 않습니다.
와 같은 비동기 호출 시간입니다.
const script = new vm.Script('setTimeout(()=>{},2000)',{ timeout: 50 }); ....
上述代码,并不是会在 50ms 后抛出异常,因为 50ms 上边的代码同步执行肯定完了,而 setTimeout 所用的时间并不算在内,也就是说 vm 模块没有办法对异步代码直接限制执行时间。我们也不能额外通过一个 timer 去检查超时,因为检查了执行中的 vm 也没有方法去中止掉。
另外,在 Node.js 通过 vm.runInContext 看起来似乎隔离了代码执行环境,但实际上却很容易「逃逸」出去。
const vm = require('vm'); const sandbox = {}; const script = new vm.Script('this.constructor.constructor("return process")().exit()'); const context = vm.createContext(sandbox); script.runInContext(context);
执行上边的代码,宿主程序立即就会「退出」,sandbox 是在 VM 之外的环境创建的,需 VM 中的代码的 this 指向的也是 sandbox,那么
//this.constructor 就是外所的 Object 构建函数 const ObjConstructor = this.constructor; //ObjConstructor 的 constructor 就是外包的 Function const Function = ObjConstructor.constructor; //创建一个函数,并执行它,返回全局 process 全局对象 const process = (new Function('return process'))(); //退出当前进程 process.exit();
没有人愿意用户一段脚本就能让应用挂掉吧。除了退出进程序之外,实际上还能干更多的事情。
有个简单的方法就能避免通过 this.constructor 拿到 process,如下:
const vm = require('vm'); //创建一外无 proto 的空白对象作为 sandbox const sandbox = Object.create(null); const script = new vm.Script('...'); const context = vm.createContext(sandbox); script.runInContext(context);
但还是有风险的,由于 JavaScript 本身的动态的特点,各种黑魔法防不胜防。事实 Node.js 的官方文档中也提到 VM 当做一个安全的沙箱去执行任意非信任的代码。
有哪些做了进一步工作的社区模块?
在社区中有一些开源的模块用于运行不信任代码,例如 sandbox、vm2、jailed 等。相比较而言 vm2 对各方面做了更多的安全工作,相对安全些。
从 vm2 的官方 READM 中可以看到,它基于 Node.js 内建的 VM 模块,来建立基础的沙箱环境,然后同时使用上了文介绍过的 ES6 的 Proxy 技术来防止沙箱脚本逃逸。
用同样的测试代码来试试 vm2
const { VM } = require('vm2'); new VM().run('this.constructor.constructor("return process")().exit()');
如上代码,并没有成功结束掉宿主程序,vm2 官方 REAME 中说「vm2 是一个沙盒,可以在 Node.js 中按全的执行不受信任的代码」。
然而,事实上我们还是可以干一些「坏」事情,比如:
const { VM } = require('vm2'); const vm = new VM({ timeout: 1000, sandbox: {}}); vm.run('new Promise(()=>{})');
上边的代码将永远不会执行结束,如同 Node.js 内建模块一样 vm2 的 timeout 对异步操作是无效的。同时,vm2 也不能额外通过一个 timer 去检查超时,因为它也没有办法将执行中的 vm 终止掉。这会一点点耗费完服务器的资源,让你的应用挂掉。
那么或许你会想,我们能不能在上边的 sandbox 中放一个假的 Promise 从而禁掉 Promise 呢?答案是能提供一个「假」的 Promise,但却没有办法完成禁掉 Promise,比如
const { VM } = require('vm2'); const vm = new VM({ timeout: 1000, sandbox: { Promise: function(){}} }); vm.run('Promise = (async function(){})().constructor;new Promise(()=>{});');
可以看到通过一行 Promise = (async function(){})().constructor 就可以轻松再次拿到 Promise 了。从另一个层面来看,况且或许有时我们还想让自定义脚本支持异步处理呢。
如何建立一个更安全一些的沙箱?
通过上文的探究,我们并没有找到一个完美的方案在 Node.js 建立安全的隔离的沙箱。其中 vm2 做了不少处理,相对来讲算是较安全的方案了,但问题也很明显,比如异步不能检查超时的问题、和宿主程序在相同进程的问题。
没有进程隔离时,通过 VM 创建的 sanbox 大体是这样的
那么,我们是不是可以尝试,将非受信代码,通过 vm2 这个模块隔离在一个独立的进程中执行呢?然后,执行超时时,直接将隔离的进程干掉,但这里我们需要考虑如下几个问题
通过进程池统调度管理沙箱进程
如果来一个执行任务,创建一个进程,用完销毁,仅处理进程的开销就已经稍大了,并且也不能不设限的开新进程和宿主应用抢资源,那么,需要建一个进程池,所有任务到来会创建一个 Script 实例,先进入一个 pending 队列,然后直接将 script 实例的 defer 对象返回,调用处就能 await 执行结果了,然后由 sandbox master 根据工程进程的空闲程序来调度执行,master 会将 script 的执行信息,包括重要的 ScriptId,发送给空闲的 worker,worker 执行完成后会将「结果 + script 信息」回传给 master,master 通过 ScriptId 识别是哪个脚本执行完毕了,就是结果进行 resolve 或 reject 处理。
这样,通过「进程池」即能降低「进程来回创建和销毁的开销」,也能确保不过度抢占宿主资源,同时,在异步操作超时,还能将工程进程直接杀掉,同时,master 将发现一个工程进程挂掉,会立即创建替补进程。
处理的数据和结果,还有公开给沙箱的方法
进程间如何通讯,需要「动态代码」处理数据可以直接序列化后通过 IPC 发送给隔离 Sandbox 进程,执行结果一样经过序列化通过 IPC 传输。
其中,如果想法公开一个方法给 sandbox,因为不在一个进程,并不能方便的将一个方案的引用传递给 sandbox。我们可以将宿主的方法,在传递给 sandbox worker 之类做一下处理,转换为一个「描述对象」,包括了允许 sandbox 调用的方法信息,然后将信息,如同其它数据一样发送给 worker 进程,worker 收到数据后,识出来所「方法描述对象」,然后在 worker 进程中的 sandbox 对象上建立代理方法,代理方法同样通过 IPC 和 master 通讯。
最终,我们建立了一个大约这样的「沙箱环境」
如此这般处理起来是不是感觉很麻烦?但我们就有了一个更加安全一些的沙箱环境了,这些处理。笔者已经基于 TypeScript 编写,并封装为一个独立的模块 Safeify。
GitHub: https://github.com/Houfeng/safeify,欢迎 Star & Issues
最后,简单介绍一下 Safeify 如何使用,通过如下命令安装
npm i safeify --save
在应用中使用,还是比较简单的,如下代码(TypeScript 中类似)
import { Safeify } from './Safeify'; const safeVm = new Safeify({ timeout: 50, //超时时间,默认 50ms asyncTimeout: 500, //包含异步操作的超时时间,默认 500ms quantity: 4 //沙箱进程数量,默认同 CPU 核数 }); const context = { a: 1, b: 2, add(a, b) { return a + b; } }; const rs = await safeVm.run(`return add(a,b)`, context); console.log('result',rs);
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
위 내용은 Node.js 애플리케이션을 위한 샌드박스 환경을 설정하는 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

Python 및 JavaScript의 미래 추세에는 다음이 포함됩니다. 1. Python은 과학 컴퓨팅 분야에서의 위치를 통합하고 AI, 2. JavaScript는 웹 기술의 개발을 촉진하고, 3. 교차 플랫폼 개발이 핫한 주제가되고 4. 성능 최적화가 중점을 둘 것입니다. 둘 다 해당 분야에서 응용 프로그램 시나리오를 계속 확장하고 성능이 더 많은 혁신을 일으킬 것입니다.

개발 환경에서 Python과 JavaScript의 선택이 모두 중요합니다. 1) Python의 개발 환경에는 Pycharm, Jupyternotebook 및 Anaconda가 포함되어 있으며 데이터 과학 및 빠른 프로토 타이핑에 적합합니다. 2) JavaScript의 개발 환경에는 Node.js, VScode 및 Webpack이 포함되어 있으며 프론트 엔드 및 백엔드 개발에 적합합니다. 프로젝트 요구에 따라 올바른 도구를 선택하면 개발 효율성과 프로젝트 성공률이 향상 될 수 있습니다.

예, JavaScript의 엔진 코어는 C로 작성되었습니다. 1) C 언어는 효율적인 성능과 기본 제어를 제공하며, 이는 JavaScript 엔진 개발에 적합합니다. 2) V8 엔진을 예를 들어, 핵심은 C로 작성되며 C의 효율성 및 객체 지향적 특성을 결합하여 C로 작성됩니다.

JavaScript는 웹 페이지의 상호 작용과 역학을 향상시키기 때문에 현대 웹 사이트의 핵심입니다. 1) 페이지를 새로 고치지 않고 콘텐츠를 변경할 수 있습니다. 2) Domapi를 통해 웹 페이지 조작, 3) 애니메이션 및 드래그 앤 드롭과 같은 복잡한 대화식 효과를 지원합니다. 4) 성능 및 모범 사례를 최적화하여 사용자 경험을 향상시킵니다.

C 및 JavaScript는 WebAssembly를 통한 상호 운용성을 달성합니다. 1) C 코드는 WebAssembly 모듈로 컴파일되어 컴퓨팅 전력을 향상시키기 위해 JavaScript 환경에 도입됩니다. 2) 게임 개발에서 C는 물리 엔진 및 그래픽 렌더링을 처리하며 JavaScript는 게임 로직 및 사용자 인터페이스를 담당합니다.

JavaScript는 웹 사이트, 모바일 응용 프로그램, 데스크탑 응용 프로그램 및 서버 측 프로그래밍에서 널리 사용됩니다. 1) 웹 사이트 개발에서 JavaScript는 HTML 및 CSS와 함께 DOM을 운영하여 동적 효과를 달성하고 jQuery 및 React와 같은 프레임 워크를 지원합니다. 2) 반응 및 이온 성을 통해 JavaScript는 크로스 플랫폼 모바일 애플리케이션을 개발하는 데 사용됩니다. 3) 전자 프레임 워크를 사용하면 JavaScript가 데스크탑 애플리케이션을 구축 할 수 있습니다. 4) node.js는 JavaScript가 서버 측에서 실행되도록하고 동시 요청이 높은 높은 요청을 지원합니다.

Python은 데이터 과학 및 자동화에 더 적합한 반면 JavaScript는 프론트 엔드 및 풀 스택 개발에 더 적합합니다. 1. Python은 데이터 처리 및 모델링을 위해 Numpy 및 Pandas와 같은 라이브러리를 사용하여 데이터 과학 및 기계 학습에서 잘 수행됩니다. 2. 파이썬은 간결하고 자동화 및 스크립팅이 효율적입니다. 3. JavaScript는 프론트 엔드 개발에 없어서는 안될 것이며 동적 웹 페이지 및 단일 페이지 응용 프로그램을 구축하는 데 사용됩니다. 4. JavaScript는 Node.js를 통해 백엔드 개발에 역할을하며 전체 스택 개발을 지원합니다.

C와 C는 주로 통역사와 JIT 컴파일러를 구현하는 데 사용되는 JavaScript 엔진에서 중요한 역할을합니다. 1) C는 JavaScript 소스 코드를 구문 분석하고 추상 구문 트리를 생성하는 데 사용됩니다. 2) C는 바이트 코드 생성 및 실행을 담당합니다. 3) C는 JIT 컴파일러를 구현하고 런타임에 핫스팟 코드를 최적화하고 컴파일하며 JavaScript의 실행 효율을 크게 향상시킵니다.


핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

Video Face Swap
완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

안전한 시험 브라우저
안전한 시험 브라우저는 온라인 시험을 안전하게 치르기 위한 보안 브라우저 환경입니다. 이 소프트웨어는 모든 컴퓨터를 안전한 워크스테이션으로 바꿔줍니다. 이는 모든 유틸리티에 대한 액세스를 제어하고 학생들이 승인되지 않은 리소스를 사용하는 것을 방지합니다.

VSCode Windows 64비트 다운로드
Microsoft에서 출시한 강력한 무료 IDE 편집기

WebStorm Mac 버전
유용한 JavaScript 개발 도구

PhpStorm 맥 버전
최신(2018.2.1) 전문 PHP 통합 개발 도구
