Chrome의 확장 프로그램 시스템은 상당히 엄격한 기본 콘텐츠 보안 정책(CSP)을 적용합니다.
정책 제한은 간단합니다. 스크립트를 줄 바깥으로 별도로 옮겨야 함
addEventListener
를 사용하도록 JavaScript 파일과 인라인 이벤트 핸들러를 변환해야 하며, eval()
는
사용 중지됩니다. Chrome 앱에는 더욱 엄격한 정책이 적용되며 Google은
속성에 따라 다릅니다.
하지만 다양한 라이브러리가 다음과 같은 eval()
및 eval
와 유사한 구조를 사용한다는 것을 알고 있습니다.
new Function()
: 성능 최적화 및 표현 용이성 템플릿 라이브러리는
이러한 구현 스타일에 특히 취약합니다. 일부 프레임워크(예: Angular.js)는 기본적으로 CSP를 지원하지만, 많은 인기 프레임워크는 아직 확장 프로그램의 eval
없는 환경과 호환되는 메커니즘으로 업데이트하지 않았습니다. 따라서 해당 기능에 대한 지원을 중단하는 것이 더 많은 것으로 입증되었습니다.
문제가 될 수 있습니다.
이 문서에서는 이러한 라이브러리를 프로젝트에 포함하는 안전한 메커니즘인 샌드박스를 소개합니다. 데이터에 대해 걱정할 필요가 없습니다. 간결함을 위해 여기서는 확장이라는 용어를 사용하겠지만 개념이 애플리케이션에 동일하게 적용됩니다
샌드박스를 사용해야 하는 이유
eval
은 확장 프로그램 내에서 위험합니다. 실행되는 코드가 확장 프로그램의 높은 권한 환경에 있는 모든 항목에 액세스할 수 있기 때문입니다. 사용자의 보안 및 개인 정보 보호에 심각한 영향을 미칠 수 있는 강력한 chrome.*
API가 많이 있습니다. 단순한 데이터 유출은 가장 작은 문제입니다.
제공되는 솔루션은 eval
가 확장 프로그램의 데이터 또는 확장 프로그램의 가치가 높은 API에 액세스하지 않고도 코드를 실행할 수 있는 샌드박스입니다. 데이터도, API도, 문제도 없습니다.
이를 위해 확장 프로그램 패키지 내에서 특정 HTML 파일을 샌드박스 처리된 것으로 표시합니다.
샌드박스 페이지가 로드될 때마다 고유한 출처로 이동되며 chrome.*
API에 대한 액세스가 거부됩니다. 이 샌드박스 페이지를 iframe
를 통해 확장 프로그램에 로드하면 메시지를 전달하고, 메시지에 어떤 식으로든 작업하도록 하며, 결과를 다시 전달할 때까지 기다릴 수 있습니다. 이 간단한 메시지 메커니즘은 eval
기반의 안전한 포함하는 데 필요한 모든 것을 제공합니다.
코드를 작성해야 합니다.
샌드박스 생성 및 사용
바로 코드를 작성하려면 샌드박스 샘플 확장 프로그램을 다운로드하여 사용 중지합니다. 이는 핸들바 위에 빌드된 작은 메시지 API의 실제 예입니다. 이 템플릿 라이브러리에는 시작하는 데 필요한 모든 것이 들어 있습니다. 좀 더 자세한 설명을 원하는 경우 여기에서 샘플을 함께 살펴보겠습니다.
매니페스트의 파일 나열
샌드박스 내에서 실행되어야 하는 각 파일은 sandbox
속성을 추가하여 확장 프로그램 매니페스트에 나열되어야 합니다. 이 단계는 매우 중요하며 간과하기 쉽습니다. 따라서 샌드박스 파일이 매니페스트에 표시되는지 다시 확인하세요. 이 샘플에서는 파일을 스마트하게 샌드박스 처리하여
'sandbox.html'이라고 되어 있습니다 매니페스트 항목은 다음과 같습니다.
{
...,
"sandbox": {
"pages": ["sandbox.html"]
},
...
}
샌드박스 파일 로드
샌드박스 파일에서 흥미로운 작업을 하려면 다음과 같은 컨텍스트에서 로드해야 합니다.
확장 프로그램의 코드로 해결할 수 있습니다. 여기서 sandbox.html은 iframe
를 통해 확장 프로그램의 이벤트 페이지(eventpage.html)에 로드되었습니다. eventpage.js에는 페이지에서 iframe
를 찾아 contentWindow
에서 postMessage
메서드를 실행하여 브라우저 작업이 클릭될 때마다 샌드박스로 메시지를 전송하는 코드가 포함되어 있습니다. 메시지는 context
및 command
의 두 가지 속성을 포함하는 객체입니다. 잠시 후 두 가지 모두 자세히 살펴보겠습니다.
chrome.browserAction.onClicked.addListener(function() {
var iframe = document.getElementById('theFrame');
var message = {
command: 'render',
context: {thing: 'world'}
};
iframe.contentWindow.postMessage(message, '*');
});
postMessage
API에 관한 일반적인 정보는 MDN의 postMessage
문서를 참고하세요. 매우 완성도 높고 읽을 만한 가치가 있습니다. 특히 데이터는 직렬화 가능한 경우에만 앞뒤로 전달할 수 있습니다. 예를 들어 함수는 그렇지 않습니다.위험한 행동
sandbox.html
가 로드되면 Handlebars 라이브러리를 로드하고 Handlebars에서 제안하는 방식으로 인라인 템플릿을 만들고 컴파일합니다.
<script src="handlebars-1.0.0.beta.6.js"></script>
<script id="hello-world-template" type="text/x-handlebars-template">
<div class="entry">
<h1>Hello, !</h1>
</div>
</script>
<script>
var templates = [];
var source = document.getElementById('hello-world-template').innerHTML;
templates['hello'] = Handlebars.compile(source);
</script>
실패하지 않습니다. Handlebars.compile
가 new Function
를 사용하게 되더라도 예상대로 작동하며 templates['hello']
에 컴파일된 템플릿이 생성됩니다.
결과를 다시 전달합니다.
이벤트 페이지의 명령어를 수락하는 메시지 리스너를 설정하여 이 템플릿을 사용할 수 있도록 합니다. 전달된 command
를 사용하여 실행해야 할 작업을 결정합니다. 단순히 렌더링하는 것 이상을 할 수 있습니다. 템플릿을 만드는 것이 context
는 렌더링을 위해 템플릿에 직접 전달됩니다. 렌더링된 HTML은 확장 프로그램이 나중에 유용한 작업을 할 수 있도록 이벤트 페이지로 다시 전달됩니다.
<script>
window.addEventListener('message', function(event) {
var command = event.data.command;
var name = event.data.name || 'hello';
switch(command) {
case 'render':
event.source.postMessage({
name: name,
html: templates[name](event.data.context)
}, event.origin);
break;
// case 'somethingElse':
// ...
}
});
</script>
이벤트 페이지로 돌아가면 이 메시지가 수신되고 전달된 html
데이터로 흥미로운 작업을 실행합니다. 이 경우 데스크톱 알림을 통해 에코 처리하지만 이 HTML을 확장 프로그램 UI의 일부로 안전하게 사용할 수도 있습니다. innerHTML
를 통해 삽입해도 심각한 보안 위험이 발생하지 않습니다. 어떤 영리한 공격을 통해 샌드박스 코드를 완전히 손상시켜도 위험한 스크립트나 플러그인 콘텐츠를 권한이 높은 확장 프로그램 컨텍스트에 삽입할 수 없기 때문입니다.
이 메커니즘을 사용하면 템플릿을 간편하게 만들 수 있지만 물론 템플릿에만 국한되지 않습니다. 모든 문자 엄격한 콘텐츠 보안 정책에 따라 즉시 작동하지 않는 코드는 샌드박스될 수 있습니다. 인치 제대로 실행될 수 있는 확장 프로그램의 구성요소를 샌드박스에서 실행하는 것이 유용할 때가 많습니다. 프로그램의 각 조각을 하는 데 필요한 최소한의 권한 집합으로 제한하기 위해 실행할 수 있습니다 Google I/O 2012의 Writing Secure Web Apps and Chrome Extensions 프레젠테이션에서는 이러한 기법이 실제로 적용된 몇 가지 좋은 예를 제공하며 56분 정도 소요됩니다.