`
wgcode
  • 浏览: 591520 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

深入理解Flash的沙箱 – Application Domains_上

阅读更多

应用程序域

Application Domains 应用程序域

和安全域一样,不同安全沙箱下的SWF有着自己独立的类定义。这种在安全域下面进行划分和管理类定义(函数、接口和命名空间的定义也类似)的子域就是应用程序域。应用程序域只存在于安全域内,并且只能属于唯一的一个安全域。但是安全域可以包含多个应用程序域。

Application Domains in Security Domains
安全域内的应用程序域

虽然安全域沙箱用于保护数据安全,应用程序沙箱域用于划分定义。但是他们都用于解决定义的冲突和判断代码的继承关系。

安全域彼此之间是相互独立的,相比之下,应用程序域之间的关系则较为复杂。应用程序域通过类似于Flash中的显示列表那样的层级关系链接在一起。应用程序域可以包含任意的子域,而子域只能有一个父域。子域继承了来自父域中的定义,就像是显示列表中父对象的位置和缩放属性被子对象继承一样。

应用程序域的根节点是一个系统域,这个域包含了Flash Player API的原生定义(Array,XML,flash.display.Sprite等等)。系统域与安全域是一一对应的关系,当安全域初始化的时候这个唯一的系统域也被建立。

当一个Flash Player的实例初始化的时候,SWF文件加到它对应的安全域内。同时也创建了一个包含了这个文件中所有编译过的ActionScript定义的应用程序域。这个应用程序域就成为安全域下的系统域的第一个子域。Flash Player API的原生定义就通过这种继承关系对所有子域开放。

Child Application Domain
在系统域下新建了一个SWF应用程序域

我们将在应用程序域的继承章节中进行更多关于继承的讨论。

Application Domain Placement 应用程序域的位置

第一个实例化Flash Player的SWF文件所包含的定义总是被加载为系统域的直接子域。父SWF去加载子SWF的时候,可以控制子SWF内的定义所要放置的位置。可选的位置共有以下4种:

  1. 父SWF的应用程序域的新建子域 (默认方式)
  2. 子SWF 与父SWF的应用程序域合并
  3. 作为父域的系统域下的新建子域
  4. 在其他安全域下的系统域的新建子域

前三种情况都是把子SWF加载到父域所处的安全域下,只有第四种是唯一一种把SWF加载到其他安全域下的方法。

Application Domain Placement
加载子SWF时放置应用程序域的4种选择

还有一种没提到的方式,是你为某个已加载的SWF创建了应用程序域,再把其他子SWF中的定义合并到(或者继承)这个域的情况。这种特殊的放置方式需要复杂的应用程序域层级管理,你需要掌握ApplicationDomain.parentDomain的用法,在此提醒读者小心:这种方法通常在不同的安全沙箱下(本地或者网络)会有不同的行为。这种方式很不常见,所以在此不进行更深的探讨。

LoaderContext对象的applicationDomain属性定义了放置应用程序域的方式。你可以用ApplicationDomain.currentDomain(类似于安全域的SecurityDomain.currentDomain)或者用new关键字新建一个ApplicationDomain实例来作为参数。在ApplicationDomain的构造函数里可以为新建的域指定父域,如果这个参数没有指定,则表示将该域直接作为系统域的子域。

// 将定义放置到父SWF所在的应用程序域(当前应用程序域)
var current:ApplicationDomain = ApplicationDomain.currentDomain;
 
// 将定义放置到父SWF所在的应用程序域的的子域
var currentChild:ApplicationDomain = new ApplicationDomain(current);<em>?</em>
 
// 将定义放置到父SWF所在的应用程序域的系统域
var systemChild:ApplicationDomain = new ApplicationDomain();

下面的代码演示了使用LoaderContext对象传递ApplicationDomain实例给Loader.load方法,把一个子SWF加载到父SWF所处的应用程序域的子域下的例子。这种方式也是默认的加载行为。

var context:LoaderContext = new LoaderContext();
// 把子应用程序域作为当前应用程序域的子域
var current:ApplicationDomain = ApplicationDomain.currentDomain;
context.applicationDomain = new ApplicationDomain(current);
 
var loader:Loader = new Loader();
var url:String = "child.swf";
loader.load(new URLRequest(url), context);

ApplicationDomain实例在内部包含了不对ActionScript开放的层级位置信息。每个ApplicationDomain实例都是一个唯一引用,彼此之间不能相互比较。

var current1:ApplicationDomain = ApplicationDomain.currentDomain;
var current2:ApplicationDomain = ApplicationDomain.currentDomain;
trace(current1 == current2); // false

你也不能通过parentDomain属性得到系统域的引用,只有通过new ApplicationDomain()才可以。

Application Domain Inheritance 应用程序域的继承

定义的继承和类继承有点类似,两者都是子级可以访问父级的定义,而反之则不行。

区别在于,应用程序域的继承不允许子级覆盖父级的定义。如果子域中包含有与父域一样的定义(指的是完全限定名称一致,包括包路径)。那么父域中的定义会取代掉子域。

Child Application Domain Inheritance
子域中的定义被父域覆盖

这是因为你不能改变一个已经存在的实例的类定义。如果新的定义在被加载进来以前就已经用旧的定义生成过实例,那么这个实例原先的类定义和新的类定义之间就会产生冲突。所以Flash Player保护原先的类定义不被重写来避免冲突。

这也意味着开发者不可能覆盖ActionScript API的原生定义。因为SWF所处的应用程序域肯定是系统域的子域,而系统域包含了所有原生的定义。所以就算子SWF中包含了同名的定义,也会被系统域中的定义所覆盖。

当向一个已经存在的应用程序域合并定义时,上述规则同样适用。只有与原先的域里的定义无冲突的定义才会被合并。

Adding Definitions in Application Domain
新增到应用程序域里的定义不会覆盖现有的定义

这种情况下,那些发生冲突但却被覆盖的定义就完全获取不到了。但是如果是继承的方式,就算子域中的那些冲突定义被父域中的定义覆盖掉,还是可以通过getDefinition方法从子域中提取出来,关于这点将在动态获取定义章节中讨论。

加载到应用程序域中的定义在应用程序域的生命期里一直存在。在SWF卸载后,用于保存这个SWF内的定义的应用程序域也会从内存中卸载。但如果该SWF的定义是放在其他某个已经存在的应用程序域内的话,那么这些定义将一直存在于内存中,除非目标应用程序域所关联的那个SWF被卸载。如果一直把新的定义加载到一个已经存在的域内,比如为第一个被加载的SWF创建的域,那么定义所占用的内存就会一直增加。如果是一个不停加载子SWF的滚动广告应用的话,持续增加定义到相同的应用程序域内引起的内存增长问题显然不是预期的结果。

而且,用这种方式加载的定义不会随着子SWF的卸载而卸载,而是在第二次加载相同的子SWF的时候重用第一次加载时创建的定义。这通常不会有什么问题,但是这意味着再次加载相同SWF的时候静态类的状态不会重置。静态变量有可能是上次使用过的值,一定会和第一次加载进来的时候保持一致。

所以,不同的情况需要不同的解决方法。

Child Domains: Definition Versioning 子域:定义的版本管理

定义的继承机制使得子域可以很方便的共享父域内的定义。也由于子域中的重名定义会被父域所覆盖的原因,父应用程序域拥有控制在子域中使用哪个版本的定义的权力。

Child Application Domain Inherits Parent Definitions
子应用程序域继承自父域

考虑以下情形:一个基于SWF的网站使用不同的SWF文件来代表不同的页面。主SWF负责加载这些子页面。每个页面SWF基于一个相同的类库开发,具有相似的行为。比如都有一个PageTitle类来表示页面的标题文本。

假如在相同域下有另一个SWF也用到这些相同的子页面,但是需要把子页面的标题文本变为不可选(假设原先的属性是可选择)。要实现这个例子里的目的,在PageTitle类中,我们需要把TextField的selectable属性改为false。但这样改动的问题是会影响原先的SWF文件保持其本来的行为。

为了解决这个问题,我们可以把每个子页面都复制一份并重新编译。但这么做的话会占用更多的空间和网站流量。更好的办法是只编译第二个主SWF,把更新过的PageTitle类定义一起编译进去。然后在子页面在加载到子应用程序域的时候,这个类的定义就会被父域里的定义给覆盖。

原先所有子页面用的PageTitle类如下:

package {
	import flash.display.Sprite;
	import flash.text.TextField;
 
	public class PageTitle extends Sprite {
 
		private var title:TextField;
 
		public function PageTitle(titleText:String){
			title = new TextField();
			title.text = titleText;
			addChild(title);
		}
	}
}

编译到第二个主文件里的更新版本的PageTitle类:

package {
	import flash.display.Sprite;
	import flash.text.TextField;
 
	public class PageTitle extends Sprite {
 
		private var title:TextField;
 
		public function PageTitle(titleText:String){
			title = new TextField();
			title.text = titleText;
			<strong>title.selectable = false;</strong> // changed
			addChild(title);
		}
	}
}

把更新过的PageTitle类定义编译到新的主文件里面,并加载所有子页面到它们自己的子应用程序域中。

PageTitle; // 虽然没有直接用到PageTitle,但我们可以包含一个引用,让它被一同编译进来 
 
// 加载子页面到它们自己的子应用程序域中
// 加载的SWF将会用父域里的PageTitle定义取代掉它们自带的
function addChildPage(url:String):void {
	var context:LoaderContext = new LoaderContext();
	var current:ApplicationDomain = ApplicationDomain.currentDomain;
	context.applicationDomain = new ApplicationDomain(current);
 
	var loader:Loader = new Loader();
	addChild(loader);
	loader.load(new URLRequest(url), context);
}

这种方法可以在不用重新编译子内容的前提下改变其中的类行为,这都是由于父应用程序域中的定义会覆盖子域中的定义的原因。

注意在上面的例子也可以省略LoaderContext的使用,效果是一样的。

即便子SWF无需用作多重使用目的,更新主文件中的定义也比更新所有子文件的更加简单。实际上,子文件中甚至可以完全不用包含这些定义,只依赖于主文件提供。这就是我们将在相同的域:运行时共享库章节里将展开讨论的。

Separate Domains: Preventing Conflicts 域分离:避免冲突

某些情形下,你可能不希望加载的子SWF内容被父应用程序域里的定义继承关系所影响。因为有可能你甚至不知道父域中存在哪些定义。不论哪种情况,最好都要避免主SWF和子SWF中的定义共享。在这种情况下,应该把子SWF的定义放到新的系统域的子域下。

Child SWF Domain as Child of System Domain
系统域下的不同子应用程序域

由于父SWF和子SWF的定义之间没有继承关系,所以这时候即使存在相同的定义也不会引起冲突,因为二者属于不同的沙箱。

举个例子:比如你有个培训程序,通过加载外部SWF来代表不同的培训模块。这个程序已经有些年头了,许多开发者开发了成百上千个培训模块。这些模块,甚至培训主程序自身都是基于不同版本的基础代码库进行开发。所以主程序要保证自己使用的基础代码库不会对其他模块造成不兼容的情况。这就必须把这些培训模块加载到他们独立的系统域下的子域,而不是把他们加载到主应用程序域的子域下面。

trainingapplication.swf:

var moduleLoader:Loader = new Loader();
addChild(moduleLoader);
 
// 把模块加载到系统域的子域下,与当前的应用程序域区分开
function loadModule(url:String):void {
	var context:LoaderContext = new LoaderContext();
	context.applicationDomain = new ApplicationDomain();
 
	moduleLoader.load(new URLRequest(url), context);
}

不足的是,这种定义的划分方式还不是完全隔离的。由于在同一个安全域下的内容都处于一个相同的系统域下,任何对系统域内定义的修改都将影响同一个安全域下的所有应用程序域。即使是将子SWF加载到一个单独的系统域的子域下,父SWF对系统域的更改还是会对其造成影响。

我们可以通过改动XML.prettyIndent属性来验证这一点:不管处于应用程序域层级的哪个SWF对系统域里的定义作出改变,都会影响到相同安全域下的所有文件。

parent.swf:

trace(XML.prettyIndent); // 2
XML.prettyIndent = 5;
trace(XML.prettyIndent); // 5
 
var loader:Loader = new Loader();
 
var context:LoaderContext = new LoaderContext();
// 新建一个独立的应用程序域
context.applicationDomain = new ApplicationDomain();
 
var url:String = "child.swf";
loader.load(new URLRequest(url), context);

child.swf:

trace(XML.prettyIndent); // 5

所以最佳实践是对定义做的改动应该在使用后及时还原,这样可以避免对其他文件的影响。

var originalPrettyIndent:int = XML.prettyIndent;
XML.prettyIndent = 5;
trace(myXML.toXMLString());
XML.prettyIndent = originalPrettyIndent;

同样的,你也必须留心类似这样的值有可能在你的程序之外被人所改动。

 

分享到:
评论

相关推荐

    flash安全沙箱汇总

    随着HTML5等现代技术的兴起,Flash逐渐被淘汰,许多浏览器已经停止支持Flash,这在一定程度上降低了Flash沙箱安全问题的影响。 五、总结 Flash安全沙箱是Flash平台为了保证用户安全而设计的关键机制。它通过划分...

    flashplayer_11_plugin_debug_32bit

    标题“flashplayer_11_...总结来说,“flashplayer_11_plugin_debug_32bit”是一个专为开发和调试Flash内容设计的工具,虽然随着技术的发展,其重要性已不如从前,但对于处理旧项目或理解早期Web开发历史仍然有价值。

    用于单独开发和测试UI组件的沙箱_TypeScript_JavaScript_下载.zip

    "用于单独开发和测试UI组件的沙箱_TypeScript_JavaScript_下载.zip" 提供的正是这样一个工具,它支持使用TypeScript和JavaScript两种语言,为React UI组件的开发提供了一个安全、独立的环境。 TypeScript是...

    java ,c#,delphi 解决flash安全沙箱问题

    综上所述,处理 Flash 安全沙箱问题涉及理解沙箱模型、设置跨域策略、实现安全通信接口、管理权限、代码签名、异常处理以及遵循安全编码实践等多个方面。开发者需要在 Java, C# 和 Delphi 中综合运用这些技术来创建...

    install_flash_player_ax_30.zip

    对于仍在使用 Windows 7 或更低版本的用户,建议转而使用支持现代 web 标准的浏览器和替代技术,或者在必须使用 Flash 的情况下,采取严格的网络安全措施,例如限制浏览的网站和使用沙箱环境。同时,对于 Windows 8 ...

    要要安全沙箱(11Safe_Sandbox) v1.0.0.1.rar.cab

    backups

    install_flash_player_ppapi(无锁区)

    2. **PPAPI(Pepper Plugin API)**:是Google Chrome浏览器使用的一种插件接口,与NPAPI( Netscape Plugin Application Programming Interface)相比,PPAPI提供了更安全、更高效的环境,因为它运行在沙箱模式下,...

    深入理解ApplicationDomain和SecurityDomain

    ### 深入理解ApplicationDomain和SecurityDomain #### 安全域(Security Domain)与应用程序域(Application Domain)概述 安全域与应用程序域是Flash Player中两种重要的沙箱概念,它们帮助开发者理解如何管理和...

    flash 安全沙箱处理集合

    通过以上内容,你应该对AS3中的安全沙箱有了更深入的理解。如果你在实际项目中遇到沙箱问题,可以参考提供的文件集合,寻找解决方案。这些资料很可能包含了多种处理方法,以应对各种情况。记住,解决这类问题可能...

    Flash Socket安全沙箱策略mini服务器,解决Flash Socket安全沙箱,安全策略

    本程序为绿色mini服务程序 程序会自动打开Flash默认的843端 自动将crossdomain.xml返回给flash客户端 您可以修改crossdomain.xml中的内容,大小不要超过10K 有问题可email我

    ApplicationDomain的误解,安全沙箱有关内容

    ### ApplicationDomain的理解与安全沙箱相关知识 #### 一、ApplicationDomain的概念与作用 在Adobe Flash AS3编程中,`ApplicationDomain`是一个重要的概念,它主要用于管理类的加载和访问控制,同时也为运行时...

    Flash加载swf文件的沙箱问题

    本篇文章将详细探讨“Flash加载SWF文件的沙箱问题”,并结合标签“源码”和“工具”来深入理解这个问题。 Flash Player为了确保用户的安全,采用了沙箱模型,这个模型将不同的运行环境分隔开来,防止恶意代码对用户...

    火狐浏览器崩溃怎么办,Flash沙箱安全模式帮你轻松解决.docx

    总之,理解并正确应用Flash沙箱安全模式是解决火狐浏览器崩溃问题的一种策略,但这并不是万能的。根据具体情况,可能还需要结合其他故障排查方法,如排查硬件加速问题、内存管理等,以确保最佳的浏览器性能和稳定性...

    沙箱原理介绍,沙箱的分类

    系统级沙箱则更深入,模拟整个操作系统环境,如Windows XP/Windows 7/Linux,它能监测到更广泛的API调用,提供更全面的行为分析,适用于检测各种文件格式,包括可执行文件、文档、网页、图片、压缩文件等。...

    as3 安全沙箱 处理办法

    1. **本地沙箱**:当Flash内容从用户的本地硬盘加载时,它们运行在本地沙箱中,不能访问网络资源,但可以访问本地文件系统和硬件。 2. **网络沙箱**:如果内容从网络上加载,如通过HTTP或FTP,它们将运行在网络沙箱...

    全面认识Flex安全沙箱

    本地沙箱分为三种类型,主要用于管理运行在用户计算机上的Flash或Flex应用。这些沙箱有不同程度的权限: a) **受限本地沙箱**:这种沙箱中的SWF文件只能与本地文件系统交互,不能访问网络。这样可以防止恶意软件...

    Flash Socket策略mini服务器,迅速解决Flash socket安全策略问题,安全沙箱问题

    本程序为绿色mini服务程序 程序会自动打开Flash默认的843端口 自动将crossdomain.xml返回给flash客户端 您可以修改crossdomain.xml中的内容,大小不要超过10K

    application_security_for_the_android_platform.pdf

    本书不仅为开发者提供了深入理解安卓平台安全机制的机会,还指导他们如何构建更加安全的应用程序,保护用户数据免受威胁。 ### 安卓平台应用安全的重要性 随着智能手机和平板电脑的普及,安卓设备成为了全球最广泛...

Global site tag (gtag.js) - Google Analytics