서로 다른 보안 샌드박스의 내용 크로스 스크립팅

Adobe AIR 1.0 이상

런타임 보안 모델은 서로 다른 원본에서 코드를 분리합니다. 서로 다른 보안 샌드박스의 내용을 크로스 스크립팅하면 한 보안 샌드박스의 내용이 다른 샌드박스의 선택된 속성 및 메서드에 액세스할 수 있도록 지정할 수 있습니다.

AIR 보안 샌드박스 및 JavaScript 코드

AIR은 한 도메인의 코드가 다른 도메인의 내용과 상호 작용할 수 없는 동일 원본 정책을 적용합니다. 모든 파일은 해당 원본을 기반으로 하여 샌드박스에 배치됩니다. 원래 응용 프로그램 샌드박스의 내용은 동일 원본 원칙을 위반하고 응용 프로그램 설치 디렉토리 외부에서 로드한 내용을 크로스 스크립팅할 수 없습니다. 그러나 AIR은 비 응용 프로그램 내용을 크로스 스크립팅할 수 있는 몇 가지 기술을 제공합니다.

한 기술은 프레임 또는 iframe을 사용하여 응용 프로그램 내용을 다른 보안 샌드박스로 매핑하는 것입니다. 응용 프로그램의 샌드박싱된 영역에서 로드한 페이지는 원격 도메인에서 로드한 것처럼 동작합니다. 예를 들어 응용 프로그램 내용을 example.com 도메인으로 매핑하면 해당 내용이 example.com에서 로드된 페이지를 크로스 스크립팅할 수 있습니다.

이 기술은 응용 프로그램 내용을 다른 샌드박스에 배치하기 때문에 해당 내용 내에 있는 코드가 더 이상 평가된 문자열의 코드 실행에 대한 제한을 적용받지 않습니다. 이 샌드박스 매핑 기술을 사용하면 원격 내용을 크로스 스크립팅할 필요가 없는 경우에도 이러한 제한을 완화할 수 있습니다. 이러한 방식으로 내용을 매핑하는 기술은 많은 JavaScript 프레임워크 중 하나를 사용하거나 문자열 평가에 의존하는 기존 코드를 사용할 때 특히 유용합니다. 그러나 내용이 응용 프로그램 샌드박스 외부에서 실행될 때 신뢰할 수 없는 내용을 삽입하고 실행할 수 있는 추가 위험에 주의하고 미연에 방지해야 합니다.

동시에 다른 샌드박스에 매핑된 응용 프로그램 내용이 AIR API에 대한 액세스 권한을 상실하기 때문에 응용 프로그램 샌드박스 외부에서 실행된 코드에 AIR 기능을 표시하는 데 샌드박스 매핑 기술을 사용할 수 없습니다.

다른 크로스 스크립팅 기술을 사용하면 비 응용 프로그램 샌드박스의 내용과 응용 프로그램 샌드박스에 있는 해당 부모 문서 간의 샌드박스 브리지라고 하는 인터페이스를 만들 수 있습니다. 브리지를 통해 자식 내용이 부모가 정의한 속성 및 메서드에 액세스하거나 부모가 자식이 정의한 속성 및 메서드에 액세스할 수 있습니다. 또는 이 두 작업을 모두 수행할 수 있습니다.

마지막으로 응용 프로그램 샌드박스 및 기타 샌드박스(선택 사항)에서 크로스 도메인 XMLHttpRequests를 수행할 수도 있습니다.

자세한 내용은 HTML 프레임 및 iframe 요소, Adobe AIR의 HTML 보안XMLHttpRequest 객체를 참조하십시오.

비 응용 프로그램 샌드박스로 응용 프로그램 내용 로드

응용 프로그램 내용이 응용 프로그램 설치 디렉토리 외부에서 로드한 내용을 안전하게 크로스 스크립팅하려면 frame 또는 iframe 요소를 사용하여 응용 프로그램 내용을 외부 내용과 동일한 보안 샌드박스로 로드합니다. 원격 내용을 크로스 스크립팅할 필요가 없지만 응용 프로그램 페이지를 응용 프로그램 샌드박스 외부에 로드하려는 경우 원본 도메인과 동일하게 http://localhost/ 또는 다른 몇 가지 안전한 값을 지정하는 방법을 사용할 수 있습니다.

AIR은 프레임에 로드한 응용 프로그램 파일을 비 응용 프로그램 샌드박스로 매핑해야 할지 여부를 지정할 수 있는 프레임 요소에 새 특성인 sandboxRootdocumentRoot를 추가합니다. sandboxRoot URL 아래의 경로로 확인되는 파일은 대신 documentRoot 디렉토리에서 로드됩니다. 보안상의 이유로 이러한 방식으로 로드한 응용 프로그램 내용은 실제로 sandboxRoot URL에서 로드한 것처럼 처리됩니다.

sandboxRoot 속성은 프레임 내용을 배치할 샌드박스 및 도메인을 결정하는 데 사용할 URL을 지정합니다. file:, http: 또는 https: URL 스킴을 사용해야 합니다. 상대 URL을 지정하는 경우 내용이 응용 프로그램 샌드박스에 남습니다.

documentRoot 속성은 프레임 내용을 로드할 디렉토리를 지정합니다. file:, app: 또는 app-storage: URL 스킴을 사용해야 합니다.

다음은 원격 샌드박스 및 www.example.com 도메인에서 실행할 응용 프로그램의 sandbox 하위 디렉토리에 설치된 내용을 매핑하는 예제입니다.

<iframe 
    src="http://www.example.com/local/ui.html"  
    sandboxRoot="http://www.example.com/local/"  
    documentRoot="app:/sandbox/"> 
</iframe>

ui.html 페이지는 다음 script 태그를 사용하여 로컬 sandbox 폴더에서 javascript 파일을 로드할 수 있습니다.

<script src="http://www.example.com/local/ui.js"></script>

또한 다음과 같이 script 태그를 사용하여 원격 서버의 디렉토리에서 내용을 로드할 수 있습니다.

<script src="http://www.example.com/remote/remote.js"></script>

sandboxRoot URL는 원격 서버의 동일한 URL에서 모든 내용을 마스크 처리합니다. 위의 예제에서는 AIR이 요청을 로컬 응용 프로그램 디렉토리로 다시 매핑하기 때문에 www.example.com/local/ 또는 해당 하위 디렉토리의 원격 내용에 액세스할 수 없습니다. 요청은 페이지 탐색, XMLHttpRequest 또는 다른 내용 로드 방법에서 파생되었는지 여부에 상관없이 다시 매핑됩니다.

샌드박스 브리지 인터페이스 설정

응용 프로그램 샌드박스의 내용이 비 응용 프로그램 샌드박스의 내용에서 정의한 속성 또는 메서드에 액세스해야 하는 경우 또는 비 응용 프로그램 내용이 응용 프로그램 샌드박스의 내용에서 정의한 속성 및 메서드에 액세스해야 하는 경우 샌드박스 브리지를 사용할 수 있습니다. 자식 문서의 window 객체에 대한 childSandboxBridgeparentSandboxBridge 속성을 사용하여 브리지를 만들 수 있습니다.

자식 샌드박스 브리지 구축

childSandboxBridge 속성을 통해 자식 문서가 인터페이스를 부모 문서의 내용에 표시할 수 있습니다. 인터페이스를 표시하려면 childSandbox 속성을 자식 문서의 함수 또는 객체로 설정합니다. 그렇게 하면 부모 문서의 내용에서 객체 또는 함수에 액세스할 수 있습니다. 다음 예제에서는 자식 문서에서 실행하는 스크립트에서 함수 및 속성을 포함하는 객체를 해당 부모에 표시하는 방법을 보여 줍니다.

var interface = {}; 
interface.calculatePrice = function(){ 
    return ".45 cents"; 
} 
interface.storeID = "abc" 
window.childSandboxBridge = interface;

이 자식 내용이 "child"의 id가 할당된 iframe에 로드된 경우 프레임의 childSandboxBridge 속성을 읽어 부모 내용에서 인터페이스에 액세스할 수 있습니다.

var childInterface = document.getElementById("child").contentWindow.childSandboxBridge; 
air.trace(childInterface.calculatePrice()); //traces ".45 cents" 
air.trace(childInterface.storeID)); //traces "abc"

부모 샌드박스 브리지 구축

parentSandboxBridge 속성을 통해 부모 문서가 인터페이스를 자식 문서의 내용에 표시할 수 있습니다. 인터페이스를 표시하려면 부모 문서가 자식 문서의 parentSandbox 속성을 부모 문서에서 정의한 함수 또는 객체로 설정합니다. 그렇게 하면 자식의 내용에서 객체 또는 함수에 액세스할 수 있습니다. 다음 예제에서는 부모 프레임에서 실행하는 스크립트에서 함수를 포함하는 객체를 자식 문서에 표시하는 방법을 보여 줍니다.

var interface = {}; 
interface.save = function(text){ 
    var saveFile = air.File("app-storage:/save.txt"); 
    //write text to file 
} 
document.getElementById("child").contentWindow.parentSandboxBridge = interface;

이 인터페이스를 사용하면 자식 프레임의 내용이 save.txt라는 파일에 텍스트를 저장할 수 있지만 파일 시스템에 대한 기타 액세스 권한이 없습니다. 자식 내용은 다음과 같이 save 함수를 호출할 수 있습니다.

var textToSave = "A string."; 
window.parentSandboxBridge.save(textToSave);

응용 프로그램 내용은 가능한 가장 좁은 인터페이스를 다른 샌드박스에 표시해야 합니다. 비 응용 프로그램 내용은 실수 또는 악의적인 코드 삽입의 피해를 입을 수 있기 때문에 본질적으로 신뢰할 수 없는 것으로 간주해야 합니다. 적합한 보호 조치를 마련하여 부모 샌드박스 브리지를 통해 표시하는 인터페이스가 잘못 사용되지 않도록 해야 합니다.

페이지를 로드하는 동안 부모 샌드박스 브리지에 액세스

자식 문서의 스크립트에서 부모 샌드박스 브리지에 액세스하기 위해서는 스크립트를 실행하기 전에 브리지를 설정해야 합니다. Window, 프레임 및 iframe 객체는 새 페이지 DOM이 생성되지만 스크립트가 파싱되거나 DOM 요소가 추가되기 전에 dominitialize 이벤트를 전달합니다. dominitialize 이벤트를 사용하여 자식 문서의 모든 스크립트가 액세스할 수 있도록 페이지 생성 시퀀스에서 충분히 초기에 브리지를 구축할 수 있습니다.

다음 예제에서는 자식 프레임에서 전달한 dominitialize 이벤트에 응답하여 부모 샌드박스 브리지를 만드는 방법을 보여 줍니다.

<html> 
<head> 
<script> 
var bridgeInterface = {}; 
bridgeInterface.testProperty = "Bridge engaged"; 
function engageBridge(){ 
    document.getElementById("sandbox").contentWindow.parentSandboxBridge = bridgeInterface; 
} 
</script> 
</head> 
<body> 
<iframe id="sandbox" 
            src="http://www.example.com/air/child.html"  
            documentRoot="app:/" 
            sandboxRoot="http://www.example.com/air/" 
            ondominitialize="engageBridge()"/> 
</body> 
</html>

다음 child.html 문서에서는 자식 내용이 부모 샌드박스 브리지에 액세스하는 방법을 보여 줍니다.

<html> 
    <head> 
        <script> 
            document.write(window.parentSandboxBridge.testProperty); 
        </script>   
    </head>   
    <body></body> 
</html>

프레임이 아닌 자식 윈도우의 dominitialize 이벤트를 수신하려면 window.open() 함수에서 만든 새 자식 window 객체에 리스너를 추가해야 합니다.

var childWindow = window.open(); 
childWindow.addEventListener("dominitialize", engageBridge()); 
childWindow.document.location = "http://www.example.com/air/child.html";

이 경우 응용 프로그램 내용을 비 응용 프로그램 샌드박스로 매핑할 방법은 없습니다. 이 기술은 응용 프로그램 디렉토리 외부에서 child.html을 로드한 경우에만 유용합니다. 윈도우의 응용 프로그램 내용을 비 응용 프로그램 샌드박스에 매핑할 수 있지만 먼저 자체적으로 프레임을 사용하여 자식 문서를 로드하고 해당 문서를 원하는 샌드박스로 매핑하는 중간 페이지를 로드해야 합니다.

HTMLLoader 클래스 createRootWindow() 함수를 사용하여 윈도우를 만드는 경우 새 윈도우는 createRootWindow()가 호출되는 문서의 자식이 아닙니다. 따라서 새 윈도우로 로드된 비 응용 프로그램 내용에 대한 호출 윈도우에서 샌드박스 브리지를 만들 수 없습니다. 대신 자체적으로 프레임을 사용하여 자식 문서를 로드하는 새 윈도우에서 중간 페이지를 로드해야 합니다. 그러고 나서 새 윈도우의 부모 문서에서 프레임에 로드된 자식 문서로의 브리지를 구축할 수 있습니다.