避免与安全相关的 JavaScript 错误

Adobe AIR 1.0 和更高版本

如果由于这些安全限制而限制在沙箱中使用所调用的代码,则运行时将调度 JavaScript 错误:“Adobe AIR runtime security violation for JavaScript code in the application security sandbox”(应用程序安全沙箱中存在针对 JavaScript 代码的 Adobe AIR 运行时安全侵犯)。为了避免此错误,请按照这些代码编写方法进行操作。

产生与安全相关的 JavaScript 错误的原因

一旦触发文档 load 事件并退出所有 load 事件处理函数,将限制应用程序沙箱中执行的代码执行涉及计算和执行字符串的大多数操作。如果尝试使用以下类型的可计算和执行潜在不安全字符串的 JavaScript 语句,则会生成 JavaScript 错误:

将应用程序内容映射到其他沙箱

在大多数情况下,可以改写或重构应用程序以避免与安全相关的 JavaScript 错误。但是,如果无法进行改写或重构,则可以采用 将应用程序内容加载到非应用程序沙箱 中介绍的技术将应用程序内容加载到其他沙箱。如果该内容还必须访问 AIR API,则可以按照 设置沙箱桥接口 中的说明创建一个沙箱桥。

eval() 函数

在应用程序沙箱中, eval() 函数只能用在页面 load 事件之前或用在 load 事件处理函数中。在页面加载之后,调用 eval() 将不会执行代码。但是,在下面的情况中,可以通过改写代码来避免使用 eval()

将属性分配给对象

不再通过分析字符串来构建属性存取器:

eval("obj." + propName + " = " + val);

而是使用中括号记号来访问属性:

obj[propName] = val;

创建从上下文中获得变量的函数

将如下所示的语句:

function compile(var1, var2){ 
    eval("var fn = function(){ this."+var1+"(var2) }"); 
    return fn; 
}

替换为:

function compile(var1, var2){ 
    var self = this; 
    return function(){ self[var1](var2) }; 
}

创建使用类名称作为字符串参数的对象

假设有一个 JavaScript 类,其代码定义如下:

var CustomClass =  
    { 
        Utils: 
        { 
            Parser: function(){ alert('constructor') } 
        }, 
        Data:  
        { 
         
        } 
    }; 
var constructorClassName = "CustomClass.Utils.Parser";

最简单的实例创建方法是使用 eval()

var myObj; 
eval('myObj=new ' + constructorClassName +'()')

但是,通过分析类名称的各个部分并使用中括号记号构建新对象,可以避免调用 eval()

function getter(str) 
{ 
    var obj = window; 
    var names = str.split('.'); 
    for(var i=0;i<names.length;i++){ 
        if(typeof obj[names[i]]=='undefined'){ 
            var undefstring = names[0]; 
            for(var j=1;j<=i;j++) 
                undefstring+="."+names[j]; 
            throw new Error(undefstring+" is undefined"); 
        } 
        obj = obj[names[i]]; 
    } 
    return obj; 
}

若要创建实例,可使用:

try{ 
    var Parser = getter(constructorClassName); 
    var a = new Parser(); 
    }catch(e){ 
        alert(e); 
}

setTimeout() 和 setInterval()

将作为处理函数传递的字符串替换为函数引用或对象。例如,将以下语句:

setTimeout("alert('Timeout')", 100);

替换为:

setTimeout(function(){alert('Timeout')}, 100); 

或者,如果函数要求 this 对象由调用方设置,则将以下语句:

this.appTimer = setInterval("obj.customFunction();", 100);

替换为:

var _self = this; 
this.appTimer = setInterval(function(){obj.customFunction.apply(_self);}, 100);

Function 构造函数

new Function(param, body) 的调用可以替换为内联函数声明或仅在处理页面 load 事件之前使用。

javascript: URL

在应用程序沙箱中,将忽略在使用 javascript: URL 方案的链接中定义的代码。不会生成任何不安全的 JavaScript 错误。可以将如下所示的使用 javascript: URL 的链接:

<a href="javascript:code()">Click Me</a>

替换为:

<a href="#" onclick="code()">Click Me</a>

innerHTML 和 outerHTML 语句中通过 onevent 属性分配的事件回调

使用 innerHTML 或 outerHTML 向文档的 DOM 中添加元素时,将忽略在语句内分配的任何事件回调(如 onclick onmouseover )。不会生成任何安全错误。可以改为向新元素分配 id 属性,并使用 addEventListener() 方法设置事件处理函数回调函数。

例如,在文档中给定一个目标元素,如下所示:

<div id="container"></div>

将如下所示的语句:

document.getElementById('container').innerHTML =  
    '<a href="#" onclick="code()">Click Me.</a>';

替换为:

document.getElementById('container').innerHTML = '<a href="#" id="smith">Click Me.</a>'; 
document.getElementById('smith').addEventListener("click", function() { code(); });

从应用程序安装目录外部加载 JavaScript 文件

不允许从应用程序沙箱外部加载脚本文件。不会生成任何安全错误。在应用程序沙箱中运行的所有脚本文件都必须安装在应用程序目录中。若要在页面中使用外部脚本,必须将页面映射到其他沙箱。请参阅 将应用程序内容加载到非应用程序沙箱

document.write() 和 document.writeln()

如果页面 load 事件已处理完毕,则将忽略对 document.write() document.writeln() 的调用。不会生成任何安全错误。作为一种替代方法,可以加载新文件,或者使用 DOM 操作技术替换文档的正文。

load 事件之前或 load 事件处理函数中的同步 XMLHttpRequests

在页面 load 事件之前或在 load 事件处理函数中启动的同步 XMLHttpRequests 不会返回任何内容。可以启动异步 XMLHttpRequests,但在 load 事件之前不会返回内容。在处理 load 事件之后,同步 XMLHttpRequests 才能正常工作。

动态创建的脚本元素

动态创建的脚本元素(例如,使用 innerHTML 或 document.createElement() 方法创建的元素)将被忽略。