HTML 페이지에서 실행되는 JavaScript 코드에 일반적으로 사용 가능한 기능에 액세스하지 못하도록 브라우저에서 실행중인 JavaScript를 샌드 박싱 할 수 있는지 궁금합니다.
예를 들어, “관심있는 이벤트”가 발생할 때 실행되도록 이벤트 처리기를 정의 할 수 있도록 최종 사용자에게 JavaScript API를 제공하려고하지만 해당 사용자가 window개체 의 속성과 기능에 액세스하기를 원하지 않습니다 . 내가 할 수 있습니까?
가장 간단한 경우에는 사용자가 전화를 걸지 못하게한다고 가정하겠습니다 alert. 내가 생각할 수있는 몇 가지 접근 방식은 다음과 같습니다.
window.alert세계적으로 재정의하십시오 . 페이지에서 실행중인 다른 코드 (즉, 사용자가 이벤트 핸들러에서 작성하지 않은 것)를 사용하기를 원하기 때문에 이것이 유효한 접근 방법이라고 생각하지 않습니다alert.- 처리 할 서버로 이벤트 핸들러 코드를 보냅니다. 이벤트 처리기가 페이지의 컨텍스트에서 실행되어야하기 때문에 처리 할 서버로 코드를 보내는 것이 올바른 방법인지 확실하지 않습니다.
아마도 서버가 사용자 정의 함수를 처리 한 다음 클라이언트에서 실행할 콜백을 생성하는 솔루션이 작동합니까? 이 방법이 효과가 있다고해도이 문제를 해결하는 더 좋은 방법이 있습니까?
답변
Google Caja 는 “신뢰할 수없는 타사 HTML 및 JavaScript를 페이지에 인라인으로 배치하고 안전하게 유지할 수있는 소스 간 번역기”입니다.
답변
Douglas Crockford의 ADsafe를 살펴보십시오 .
ADsafe를 사용하면 웹 페이지에 게스트 코드 (예 : 타사 스크립트 광고 또는 위젯)를 안전하게 배치 할 수 있습니다. ADsafe는 게스트 코드가 귀중한 상호 작용을 수행하는 동시에 악의적이거나 우발적 인 손상이나 침입을 방지 할 수있을 정도로 강력한 JavaScript의 하위 집합을 정의합니다. ADsafe 하위 집합은 JSLint와 같은 도구를 통해 기계적으로 확인할 수 있으므로 안전을 위해 게스트 코드를 검토하기 위해 사람의 검사가 필요하지 않습니다. ADsafe 하위 집합은 또한 우수한 코딩 방법을 적용하여 게스트 코드가 올바르게 실행될 가능성을 높입니다.
프로젝트의 GitHub 리포지토리 에서 template.html및 template.js파일 을 보면 ADsafe를 사용하는 방법의 예를 볼 수 있습니다 .
답변
웹 작업자를 사용하여 평가 된 코드를 샌드 박스로 만드는 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
}
});
답변
js.js 는 여기서 언급 할 가치가 있다고 생각합니다 . JavaScript로 작성된 JavaScript 인터프리터입니다.
기본 JS보다 약 200 배 느리지 만 특성상 완벽한 샌드 박스 환경을 만듭니다. 또 다른 단점은 크기가 거의 600kb로, 경우에 따라 데스크톱에는 적합하지만 모바일 장치에는 적합하지 않을 수 있습니다.
답변
다른 응답에서 언급했듯이 코드를 샌드 박스로 된 iframe에서 (서버 측으로 보내지 않고) 감옥에 보내고 메시지와 통신하면 충분합니다. 질문에 설명 된 것처럼 신뢰할 수없는 코드에 API를 제공해야하기 때문에 주로 만든 작은 라이브러리를 살펴 보는 것이 좋습니다 . 특정 함수 집합을 샌드 박스로 바로 내보낼 수있는 기회가 있습니다. 신뢰할 수없는 코드가 실행됩니다. 그리고 샌드 박스에서 사용자가 제출 한 코드를 실행하는 데모도 있습니다.
답변
모든 브라우저 공급 업체와 HTML5 사양은 샌드 박스 된 iframe을 허용하기 위해 실제 샌드 박스 속성을 향해 노력하고 있지만 여전히 iframe 단위로 제한됩니다.
일반적으로, 정규 표현식 등은 정지 문제로 퇴화함에 따라 임의의 사용자 제공 JavaScript를 안전하게 위생 처리 할 수 없습니다 :-/
답변
@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에서 테스트).
