辅助功能*

Jeff Swartz

Jeff Swartz

高级技术文档撰写工程师
Adobe

出版日期:
2008 年 2 月 28 日
用户级别:
中/高级
产品:
Adobe AIR

使用沙箱脚本桥

Sandbox Bridge 范例应用程序展示如何使用安全沙箱桥将在本地安装的 HTML 内容加载至网络域, 以及使用 AIR 沙箱桥使应用程序安全沙箱中的脚本与远程域中的脚本进行通信。

有关 AIR 沙箱桥的详细信息, 请参阅《用 HTML 和 Ajax 开发 Adobe AIR 应用程序》中的对不同安全沙箱中的内容进行跨脚本编写

沙箱桥示例

图 1。本范例应用程序演示如何处理原有菜单。

注意: 本范例应用程序按原样提供, 用于教学目的。

要求

若要充分利用本篇文章, 您需要以下软件和文件:

Adobe AIR

Adobe AIR SDK

范例文件:

本范例应用程序包括以下文件:

  • root.html: 应用程序主要内容。
  • ui.html: 要加载至非应用程序安全沙箱中的内容。
  • sample.css: 层叠样式表文件。
  • AIRAliases.js: AIR JavaScript 别名文件
  • application.xml: 用于 (使用 ADL 和 ADT) 调试和构建应用程序的 AIR 应用程序描述符文件。
  • AIR 图标文件范例

必备知识

应具备构建 HTML 应用程序的一般经验。有关使用此快速入门指南的详细信息, 请参阅用 HTML 构建快速入门范例应用程序

测试应用程序

Sandbox Bridge 应用程序将 HTML 内容加载至两个框架中。顶部框架包含应用程序安全沙箱中的内容, 底部框架包含来自加载至远程域中的应用程序资源目录的内容:

应用程序演示 AIR 沙箱桥的多种功能以及相关的运行时安全详细信息, 其中包括:

  • 应用程序安全沙箱中的内容有权访问所有运行时 API, 而其它沙箱中的内容无法直接调用 AIR API。
  • 应用程序安全沙箱中的内容可以通过沙箱桥对其它沙箱中的内容显示方法。同样地, 应用程序安全沙箱中的内容也可以通过沙箱桥对应用程序沙箱中的内容显示方法

了解代码

有关使用 AIR 类的详细信息, 请参阅《为 HTML 开发人员提供的 Adobe AIR 语言参考》

将应用程序资源目录中的内容加载至不同的安全域中

本应用程序构建自两个 HTML 文件: root.html 和 ui.html。root.html 文件是应用程序根文件, 在应用程序描述符文件 (application.xml) 的 initialWindow 属性中定义。将此内容加载至 AIR 应用程序安全沙箱中。然后, 此 HTML 文件将 ui.html 文件加载至一个 iframe 中。该 iframe 的属性设置定义要用于此内容的安全沙箱:

<iframe id="UI"
		    src="http://localhost/ui.html"
		    sandboxRoot="http://localhost/"
		    documentRoot="app:/"
		    width="100%" 
		    height="100%"
		    style="border: 1px solid red; margin: 0px; padding: 0px; width: 100%; height: 410px">
</iframe>

documentRoot 属性指定文件的源位置。在本例中, 将其设置为 "app:/", 这是应用程序资源目录的 URL 架构, 而此目录是安装 AIR 应用程序文件的目录。默认情况下, 将来自此目录的内容放置在应用程序安全沙箱中。但是, 在本例中, 对于此 iframe 中的内容, sandboxRoot 属性将来自一个沙箱 (在本例中为 localhost 域的沙箱) 的 URL 重新映射至 documentRoot ("app:/") 沙箱。然后, 应用程序重新解释此 iframe 中以 sandBoxRoot 路径开头的 URL, 从而返回来自 documentRoot 目录的数据。

通过将此内容放入非应用程序安全沙箱中, 此内容将获得与将其加载至应用程序安全沙箱中时不同的权限, 如以下部分所述。

应用程序安全域中内容的功能

加载 root.html 页时将其作为应用程序初始窗口的根内容。正因如此, 还会将该页自动放入应用程序安全沙箱中。应用程序安全沙箱中的内容有权访问在其它沙箱中作为被禁用内容的 AIR API。应用程序中的第一个按钮演示了这种情况。用户单击该按钮时, 应用程序成功执行对以下函数的调用:

function readApplicationDescriptorFile() {
    return air.NativeApplication.nativeApplication.applicationDescriptor;
}

air.NativeApplication.nativeApplication.applicationDescriptor 属性返回该应用程序的应用程序描述符文件中的内容, 该属性是仅限应用程序安全沙箱中内容访问的 AIR API 之一。受限制 API 的另一个示例是 FileStream 类, 该类包含用于读写本地文件系统的方法。仅限应用程序安全沙箱中内容访问的 API 在《为 HTML 开发人员提供的 Adobe AIR 语言参考》中由 AIR 徽标表明其受限性质。

从应用程序资源 URL 加载代码时, 应用程序安全沙箱中的内容只能使用可以动态地将字符串转换为代码的 API。这意味着从应用程序资源 URL 加载代码时, 应用程序内容只能调用 eval() 函数。加载此类代码之后, 应用程序内容无法调用 eval() 函数等 API。

应用程序中的第二个按钮调用来自应用程序安全沙箱中的 eval() 函数, 而这将使运行时引发异常:

try 
{
    eval("alert(44)")
}
catch (e) 
{
    alert(e)
}

如果在应用程序沙箱内允许使用动态生成的代码 (如调用 eval() 函数时生成的代码), 则会引起安全性风险。例如, 应用程序可能会在无意中执行从网络沙箱加载的字符串, 而该字符串可能包含恶意代码, 如删除或更改用户计算机上的文件或者将本地文件内容报告回不受信任的网络域的代码。

生成动态代码的方式如下所示:

  • 调用 eval() 函数。
  • 设置 innerHTML 属性或调用 DOM 函数, 以插入脚本标签, 从而直接加载资源外部的脚本。
  • 设置 innerHTML 属性或调用 DOM 函数, 以插入具有内联代码的脚本标签 (而非通过 src 加载脚本)。
  • 对于应用程序沙箱中并非来自应用程序资源目录的内容, 对其脚本标签使用 src
  • 使用 javascript URL 架构 (如 href="javascript:alert('Test')" 中所示)。

从应用程序资源加载内容时, 应用程序安全沙箱中的代码只能使用这些方法。

非应用程序安全域中内容的功能

将 ui.html 页面加载至 iframe 中, 并放置在非应用程序沙箱内 (请参阅“将应用程序资源目录中的内容加载至不同的安全域中”)。

与应用程序安全沙箱中的内容不同, 非应用程序安全沙箱中的内容在任何时候都可以调用 eval() 函数, 执行动态生成的代码。非应用程序 iframe 中的第一个按钮成功地从非应用程序安全沙箱中调用了 eval() 函数:

eval("alert(44)")

非应用程序安全沙箱中的内容无权访问仅限应用程序安全沙箱中内容访问的 AIR API。非应用程序 iframe 中的第二个按钮 (页面上的第二个框架, 红色外框) 演示了这一情况。用户单击该按钮时, 应用程序将引发 TypeError 异常:

try {
    window.runtime.flash.system.NativeApplication.nativeAppilcation.exit();
} 
catch (e) 
{
    alert(e);

}

非应用程序沙箱中的代码无权访问 window.runtime 对象, 正因如此, 此代码无法执行 AIR API。例如, window.runtime.flash.system.NativeApplication.nativeApplication.exit() 方法 (使应用程序退出) 就是仅限应用程序安全沙箱中内容访问的 AIR API 之一。用户单击第二个 iframe 中的第二个按钮 (即尝试调用 window.runtime.flash.system.NativeApplication.nativeApplication.exit() 方法) 时, 范例应用程序会引发运行时异常:

<input type="button" 
		    onclick="try {window.runtime.flash.system.Shell.shell.exit()} catch (e) {alert(e)}" 
		    value="window.runtime.flash.system.Shell.shell.exit()"/>

异常类型为 TypeError (未定义的值), 由于非应用程序沙箱中的内容无法识别 window.runtime 对象, 因此将其视为未定义的值。

不同沙箱之间的脚本通信

在某些时候, 需要用受限的方式向非应用程序内容公开一些受限的 AIR 应用程序 API。AIR 提供一种沙箱桥, 供应用程序安全沙箱向加载至其它沙箱中的 iframe 内容公开属性和方法。

窗口对象包含 parentSandboxBridge 属性, 该属性使应用程序沙箱中的脚本可以向加载至其它沙箱中的内容公开方法和属性。例如, root.html 文件包含以下代码, 这段代码公开 air.trace() 函数, 将其作为窗口对象的 parentSandBox 属性的 trace() 方法, 并公开 readApplicationDescriptorFile() 函数, 将其作为窗口对象的 parentSandBox 属性的 readApplicationDescriptorFile() 方法:

var Exposed = {};
Exposed.trace = function(str) {
    air.trace(str);
}
Exposed.readApplicationDescriptorFile = readApplicationDescriptorFile;
document.getElementById('UI').contentWindow.parentSandboxBridge = Exposed;

iframe 内容 (在非应用程序安全沙箱中) 可以访问这些方法, 具体途径是调用窗口对象的 parentSandBox 属性的 trace()readApplicationDescriptorFile() 方法。应用程序的第一个 iframe 中的第三个按钮 (在应用程序安全沙箱中) 通过调用 parentSandboxBridge.readApplicationDescriptorFile() 方法演示了这种情况:

<input type="button" onclick="alert(parentSandboxBridge.readApplicationDescriptorFile())" value="Call the exposed function for reading application.xml"/>

窗口对象还包含 childSandboxBridge 属性, 该属性使非应用程序沙箱中的脚本可以向通过 iframe 加载非应用程序内容的父应用程序内容公开方法和属性。例如, ui.html 文件包含以下代码, 这段代码公开 forApplicationSandbox() 函数, 将其作为窗口对象的 childSandBox 属性的 callMe() 方法:

childSandboxBridge = {'callMe': forApplicationSandbox};

然后, 父应用程序内容可以通过调用窗口对象的 childSandBox 属性的 callMe() 方法来访问该函数。应用程序的第一个 iframe 中的第三个按钮 (在应用程序安全沙箱中) 通过调用 callMe() 函数演示了这种情况。

<input type="button" onclick="alert(callMe())" value="Call a function from the Remote Sandbox"/>

有关详细信息, 请参阅《用 HTML 和 Ajax 开发 AIR 应用程序》中的 AIR 安全性一章。

关于作者

Jeff Swartz 于 1992 年开始他在 Macromedia (现在为 Adobe Systems)的职业生涯。目前, 他是一名 Adobe AIR 技术文档撰写工程师。Jeff 拥有伊利诺斯大学乌尔班纳-香巴尼分校的计算机科学与数学专业学士学位, 并曾就读于爱丁堡大学人工智能系。旧金山湾地区附近的听众都曾“领略”过 Jeff 在长号演奏方面的艺术风采。他还曾是 Vienna Beef Ltd. 的 Big Frank (舞蹈高手)。