programing

브라우저에서 실행되는 자바스크립트 샌드박스가 가능합니까?

easyjava 2023. 9. 26. 22:40
반응형

브라우저에서 실행되는 자바스크립트 샌드박스가 가능합니까?

HTML 페이지에서 실행되는 자바스크립트 코드에 보통 사용 가능한 기능에 접근하지 못하도록 브라우저에서 실행되는 자바스크립트를 샌드박스할 수 있는지 궁금합니다.

를 들어,에게 자바스크립트 API를 하여 "가 할 때 할 수 가 않았으면. API 를하여 "" , 를 합니다.window물건.요?제가 할 수 있을까요?

가장 가 , 를 하는 것을 alert할 수 몇 은 다음과 같습니다 제가 생각할 수 있는 몇 가지 접근 방법은 다음과 같습니다.

  • window.alert세계적으로 페이지에서인 다른 핸들러의 것)가 페이지에서 실행 중인 다른 코드(, 이벤트 핸들러의 사용자가 작성하지 않은 것) 를 사용할 수 있기 때문에 이 접근 방식이 유효하지 않을 것으로 생각합니다를 사용하고 에 이 접근 하지 않을 alert.
  • 처리할 서버에 이벤트 핸들러 코드를 보냅니다.이벤트 핸들러를 페이지의 컨텍스트에서 실행해야 하므로 처리할 코드를 서버로 전송하는 것이 올바른 방법인지 잘 모르겠습니다.

서버가 사용자가 정의한 기능을 처리한 다음 클라이언트에서 실행할 콜백을 생성하는 솔루션이 효과적일까요?그 방법이 효과가 있다 하더라도 이 문제를 해결할 더 나은 방법이 있습니까?

Google Caja는 "신뢰할 수 없는 타사 HTML 및 JavaScript를 페이지에 인라인으로 배치하고 여전히 안전하게 유지할 수 있도록 해주는" 소스-소스 간 번역기입니다.

Douglas Crockford의 ADsafe를 보십시오.

ADsafe를 사용하면 웹 페이지에 게스트 코드(예: 타사 스크립트 광고 또는 위젯)를 안전하게 넣을 수 있습니다.ADsafe는 게스트 코드가 가치 있는 상호 작용을 수행할 수 있도록 하는 동시에 악의적이거나 우발적인 손상이나 침입을 방지할 수 있을 정도로 강력한 JavaScript의 하위 집합을 정의합니다.ADsafe 서브셋은 JSlint와 같은 도구를 통해 기계적으로 확인할 수 있으므로 안전을 위해 게스트 코드를 검토하기 위해 사람이 검사할 필요가 없습니다.또한 ADsafe 서브셋은 우수한 코딩 방식을 적용하여 게스트 코드가 올바르게 실행될 가능성을 높입니다.

은 ADsafe 를를 를 볼 수 .template.html그리고.template.js프로젝트의 GitHub 저장소에 있는 파일들.

웹 워커를 이용하여 평가된 코드를 샌드박스하는 jsandbox라는 샌드박스 라이브러리를 만들었습니다.또한 샌드박스화된 코드 데이터를 명시적으로 제공하는 입력 방법을 가지고 있습니다.

다음은 API의 예입니다.

jsandbox
    .eval({
      code    : "x=1;Math.round(Math.pow(input, ++x))",
      input   : 36.565010597564445,
      callback: function(n) {
          console.log("number: ", n); // number: 1337
      }
  }).eval({
      code   : "][];.]\\ (*# ($(! ~",
      onerror: function(ex) {
          console.log("syntax error: ", ex); // syntax error: [error object]
      }
  }).eval({
      code    : '"foo"+input',
      input   : "bar",
      callback: function(str) {
          console.log("string: ", str); // string: foobar
      }
  }).eval({
      code    : "({q:1, w:2})",
      callback: function(obj) {
          console.log("object: ", obj); // object: object q=1 w=2
      }
  }).eval({
      code    : "[1, 2, 3].concat(input)",
      input   : [4, 5, 6],
      callback: function(arr) {
          console.log("array: ", arr); // array: [1, 2, 3, 4, 5, 6]
      }
  }).eval({
      code    : "function x(z){this.y=z;};new x(input)",
      input   : 4,
      callback: function(x) {
          console.log("new x: ", x); // new x: object y=4
      }
  });

RyanOHARA의 웹 워커 샌드박스 코드를 단일 파일로 개선한 버전(추가 파일 없음)eval.js파일이 필요합니다).

function safeEval(untrustedCode)
{
    return new Promise(function (resolve, reject)
        {
            var blobURL = URL.createObjectURL(new Blob([
                "(",
                function ()
                {
                    var _postMessage = postMessage;
                    var _addEventListener = addEventListener;

                    (function (obj)
                    {
                        "use strict";

                        var current = obj;
                        var keepProperties =
                        [
                            // Required
                            'Object', 'Function', 'Infinity', 'NaN', 'undefined', 'caches', 'TEMPORARY', 'PERSISTENT',
                            // Optional, but trivial to get back
                            'Array', 'Boolean', 'Number', 'String', 'Symbol',
                            // Optional
                            'Map', 'Math', 'Set',
                        ];

                        do
                        {
                            Object.getOwnPropertyNames(current).forEach(function (name)
                            {
                                if (keepProperties.indexOf(name) === -1)
                                {
                                    delete current[name];
                                }
                            });

                            current = Object.getPrototypeOf(current);
                        }
                        while (current !== Object.prototype)
                            ;

                    })(this);

                    _addEventListener("message", function (e)
                    {
                        var f = new Function("", "return (" + e.data + "\n);");
                        _postMessage(f());
                    });
                }.toString(),
                ")()"],
                {type: "application/javascript"}));

                var worker = new Worker(blobURL);

                URL.revokeObjectURL(blobURL);

                worker.onmessage = function (evt)
                {
                    worker.terminate();
                    resolve(evt.data);
                };

                worker.onerror = function (evt)
                {
                    reject(new Error(evt.message));
                };

                worker.postMessage(untrustedCode);

                setTimeout(function ()
                {
                    worker.terminate();
                    reject(new Error('The worker timed out.'));
                }, 1000);
        });
}

테스트:

https://jsfiddle.net/kp0cq6yw/

var promise = safeEval("1+2+3");

promise.then(function (result) {
                 alert(result);
             });

출력해야 합니다.6(Chrome 및 Firefox에서 테스트됨).

다른 응답에서 언급된 바와 같이, (서버 측에 코드를 보내지 않고) 샌드박스된 iframe에 코드를 가두고 메시지와 통신하는 것만으로도 충분합니다.

질문에 설명된 것처럼 신뢰할 수 없는 코드에 API를 제공할 필요가 있기 때문에 제가 만든 작은 라이브러리를 살펴볼 것을 제안합니다. 신뢰할 수 없는 코드가 실행되는 샌드박스에 특정 함수 집합을 바로 내보낼 수 있는 기회가 있습니다.사용자가 제출한 코드를 샌드박스에서 실행하는 데모도 있습니다.

http://asvd.github.io/jailed/demos/web/console/

저는 js.js가 여기서 언급할 가치가 있다고 생각합니다.자바스크립트로 작성된 자바스크립트 인터프리터입니다.

네이티브 자바스크립트보다 약 200배 느리지만, 특성상 완벽한 샌드박스 환경입니다.또 다른 단점은 크기가 약 600KB로 데스크톱의 경우에는 허용될 수 있지만 모바일 장치의 경우에는 허용되지 않습니다.

모든 브라우저 공급업체와 HTML5 사양은 iframe을 샌드박스할 수 있도록 실제 sandbox 속성을 위해 노력하고 있지만 여전히 iframe의 세분화로 제한되어 있습니다.

일반적으로 임의의 사용자가 제공하는 자바스크립트가 정지문제로 전락하면서 어느 정도의 정규표현 등도 안전하게 위생할 수 없습니다 :-/

추한 방법이지만, 아마 당신에게 이 방법이 효과가 있을 겁니다.

나는 모든 글로벌을 가져다가 샌드박스 범위에서 재정의했고, 익명 기능을 사용하여 글로벌 객체를 얻을 수 없도록 strict mode를 추가했습니다.

function construct(constructor, args) {
  function F() {
      return constructor.apply(this, args);
  }
  F.prototype = constructor.prototype;
  return new F();
}
// Sanboxer
function sandboxcode(string, inject) {
  "use strict";
  var globals = [];
  for (var i in window) {
    // <--REMOVE THIS CONDITION
    if (i != "console")
    // REMOVE THIS CONDITION -->
    globals.push(i);
  }
  globals.push('"use strict";\n'+string);
  return construct(Function, globals).apply(inject ? inject : {});
}
sandboxcode('console.log( this, window, top , self, parent, this["jQuery"], (function(){return this;}()));');
// => Object {} undefined undefined undefined undefined undefined undefined
console.log("return of this", sandboxcode('return this;', {window:"sanboxed code"}));
// => Object {window: "sanboxed code"}

https://gist.github.com/alejandrolechuga/9381781

독립적인 자바스크립트 인터프리터는 내장된 브라우저 구현의 케이지 버전보다 강력한 샌드박스를 제공할 가능성이 더 높습니다.

라이언은 이미 js.js언급했지만, 더 최신 프로젝트는 JS-Interpreter입니다.이 문서에서는 다양한 기능을 인터프리터에 노출하는 방법을 다루지만, 그 범위는 매우 제한적입니다.

2019년 현재, vm2Node.js에서 JavaScript를 실행하는 데 가장 인기 있고 정기적으로 업데이트되는 솔루션으로 보입니다.저는 프론트엔드 솔루션에 대해 잘 모릅니다.

NISP를 사용하면 샌드박스된 평가를 수행할 수 있습니다.

당신이 쓰는 표현이 정확히 자바스크립트 코드는 아니지만, 대신에 당신은 S표현을 쓸 것입니다.이것은 광범위한 프로그래밍을 요구하지 않는 간단한 DSL에 이상적입니다.

  1. 실행할 코드가 있다고 가정합니다.

     var sCode = "alert(document)";
    

    이제 샌드박스에서 실행할 경우를 가정해 보겠습니다.

     new Function("window", "with(window){" + sCode + "}")({});
    

    "샌드박스"에서 "경고" 기능을 사용할 수 없기 때문에 실행 시 이 두 줄은 실패합니다.

  2. 이제 사용자의 기능을 사용하여 창 개체의 멤버를 노출하려고 합니다.

     new Function("window", "with(window){" + sCode + "}")({
         'alert':function(sString){document.title = sString}
     });
    

물론 견적서를 추가해서 다른 광택을 낼 수도 있지만, 그 생각은 분명하다고 생각합니다.

이 사용자 자바스크립트 코드는 어디에서 오는 것입니까?

사용자가 페이지에 코드를 삽입한 다음 브라우저에서 코드를 호출하는 경우(그리스 몽키 참조) 할 수 있는 일은 많지 않습니다.그냥 브라우저가 하는 일입니다.

그러나 스크립트를 데이터베이스에 저장한 후 검색하여 평가()하면 스크립트를 실행하기 전에 정리할 수 있습니다.

모든 창을 제거하는 코드의 예.그리고 문서.참조:

 eval(
  unsafeUserScript
    .replace(/\/\/.+\n|\/\*.*\*\/, '') // Clear all comments
    .replace(/\s(window|document)\s*[\;\)\.]/, '') // Removes window. Or window; or window)
 )

이를 통해 다음이 실행(테스트되지 않음)되지 않도록 합니다.

window.location = 'http://example.com';
var w = window;

안전하지 않은 사용자 스크립트에 적용해야 하는 많은 제한 사항이 있습니다.유감스럽게도 자바스크립트에 사용할 수 있는 '샌드박스 컨테이너'가 없습니다.

저는 사용자들이 제 사이트를 위해 애플릿을 만들 수 있도록 단순화된 자바스크립트 샌드박스를 만들고 있습니다.DOM 액세스를 허용하는 문제(parentNode에서는 보안을 유지할 수 없음 =/)에 직면해 있지만, 제 접근 방식은 일부 유용한/harmless 멤버로 창 개체를 재정의한 다음 이 재정의된 창을 기본 범위로 사용자 코드를 ()하는 것이었습니다.

내 '핵심' 코드는 이렇게 돼요(나는 그것을 완전히 보여주지 않습니다 ;)

function Sandbox(parent){

    this.scope = {
        window: {
            alert: function(str){
                alert("Overriden Alert: " + str);
            },
            prompt: function(message, defaultValue){
                return prompt("Overriden Prompt:" + message, defaultValue);
            },
            document: null,
            .
            .
            .
            .
        }
    };

    this.execute = function(codestring){

        // Here some code sanitizing, please

        with (this.scope) {
            with (window) {
                eval(codestring);
            }
        }
    };
}

그래서 샌드박스를 인스턴스화하고 실행() 기능을 사용하여 코드를 실행할 수 있습니다.또한 eval'd 코드 내의 모든 새로운 선언 변수는 궁극적으로 execute() 범위에 바인딩되므로 이름이 충돌하거나 기존 코드를 엉망으로 만들지 않습니다.

글로벌 개체는 여전히 액세스할 수 있지만 샌드박스 코드를 알 수 없는 개체는 샌드박스::scope 개체에서 프록시로 정의해야 합니다.

수 있습니다. 그러면 는 . 그러면 다음과 같습니다.undefined 시시:

(function (alert) {

alert ("uh oh!"); // User code

}) ();

물론 영리한 공격자는 자바스크립트 DOM을 검사하고 창에 대한 참조가 포함된 무시되지 않는 객체를 찾음으로써 이 문제를 해결할 수 있습니다.


또 다른 아이디어는 JSlint와 같은 도구를 사용하여 사용자의 코드를 스캔하는 것입니다.미리 설정된 변수가 없는지(또는 원하는 변수만) 확인한 다음 글로벌이 설정되거나 액세스되는 경우 사용자의 스크립트가 사용되지 않도록 합니다.다시 말해서, 사용자가 리터럴을 사용하여 구성할 수 있는 객체는 샌드박스를 탈출하기 위해 접근할 수 있는 윈도우 객체에 대한 암시적 참조를 가질 수 있습니다.

언급URL : https://stackoverflow.com/questions/195149/is-it-possible-to-sandbox-javascript-running-in-the-browser

반응형