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에서 테스트).
