Unikanie błędów JavaScript związanych z bezpieczeństwem



Jeśli wywołany zostanie kod, którego użycie zostało ograniczone ze względu na ograniczenia bezpieczeństwa, środowisko wykonawcze zgłosi błąd JavaScript o następującej treści: „Naruszenie zabezpieczeń środowiska wykonawczego Adobe AIR dla kodu JavaScript w obszarze izolowanym zabezpieczeń aplikacji”. Aby uniknąć tego błędu, należy zastosować poniższe praktyki kodowania.

Przyczyny błędów JavaScript związanych z bezpieczeństwem

Dostęp kodu wykonywanego w obszarze izolowanym aplikacji jest ograniczony dla większości operacji, które dotyczą interpretacji i wykonania ciągów znaków po uruchomieniu zdarzenia load dokumentu i zakończenia działania dowolnego modułu obsługi zdarzeń load. Próba użycia poniższych typów instrukcji JavaScript, które interpretują i wykonują potencjalnie niebezpieczne ciągi znaków generują błędy JavaScript:

Odwzorowywanie treści aplikacji w różnych obszarach izolowanych

W większości przypadków programista może ponownie napisać lub zmienić strukturę aplikacji w celu uniknięcia błędów JavaScript związanych z bezpieczeństwem. Jeśli jednak ponowne napisanie lub zmiana struktury nie jest możliwa, treść aplikacji można załadować do innego obszaru izolowanego za pomocą techniki opisanej w sekcji Ładowanie treści aplikacji do nieaplikacyjnego obszaru izolowanego. Jeśli treść również musi mieć dostęp do interfejsów API środowiska AIR, należy wówczas utworzyć most obszaru izolowanego w sposób opisany w sekcji Konfigurowanie interfejsu mostu obszaru izolowanego.

Funkcja eval()

W obszarze izolowanym aplikacji funkcja eval() może być używana jedynie przed zdarzeniem load strony lub w czasie działania modułu obsługi zdarzeń load. Po załadowaniu strony wywołanie funkcji eval() nie spowoduje wykonania kodu. Jednak w poniższych przypadkach można ponownie napisać kod, aby uniknąć użycia funkcji eval().

Przypisywanie właściwości do obiektu

Zamiast przekształcać ciąg znaków w celu utworzenia akcesora właściwości:

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

do dostępu do właściwości należy użyć notacji z nawiasami:

obj[propName] = val;

Tworzenie funkcji ze zmiennymi dostępnymi kontekstowo

Zastąp instrukcje w następujący sposób:

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

na:

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

Tworzenie obiektu z użyciem nazwy klasy jako parametru w postaci ciągu znaków

Rozważmy hipotetyczną klasę JavaScript zdefiniowaną za pomocą poniższego kodu:

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

Najprostszym sposobem na utworzenie instancji będzie użycie funkcji eval():

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

Można jednak uniknąć wywołania funkcji eval() przez przekształcenie każdego składnika o danej nazwie klasy i utworzenie nowego obiektu za pomocą notacji z nawiasami:

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; 
}

Aby utworzyć instancję, użyj:

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

setTimeout() i setInterval()

Zastąp ciąg znaków przekazany jako funkcja modułu obsługi odwołaniem funkcji lub obiektem. Na przykład: zastąp instrukcję:

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

na:

setTimeout(alert('Timeout'), 10); 

Lub jeśli funkcja wymaga, aby obiekt this był ustawiony przez obiekt wywołujący, zastąp instrukcję:

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

na następującą:

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

Konstruktor funkcji

Wywołanie new Function(param, body) można zastąpić dołączoną deklaracją funkcji lub użyć go wyłącznie przed obsługą zdarzenia load strony.

Adresy URL javascript:

Kod zdefiniowany w łączu za pomocą schematu URL javascript: jest ignorowany w obszarze izolowanym aplikacji. Nie jest generowany żaden niebezpieczny błąd JavaScript. Łącza można zastąpić za pomocą adresów URL javascript: w sposób przedstawiony poniżej:

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

na:

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

Wywołania zwrotne zdarzenia przypisane za pomocą atrybutu onevent w instrukcjach innerHTML i outerHTML

Korzystając z instrukcji innerHTML lub outerHTML do dodawania elementów do modelu DOM dokumentu, dowolne wywołania zwrotne zdarzenia przypisanego w instrukcji (np. onclick lub onmouseover) zostaną zignorowane. Nie zostanie wygenerowany żaden błąd dotyczący bezpieczeństwa. Zamiast tego można przypisać atrybut id do nowych elementów i ustawić funkcje wywołania zwrotnego dla modułu obsługi zdarzeń za pomocą metody addEventListener().

Na przykład: dany element docelowy w dokumencie:

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

Zastępuje instrukcje:

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

na:

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

Ładowanie plików JavaScript spoza katalogu instalacyjnego aplikacji

Ładowanie plików skryptu spoza obszaru izolowanego aplikacji jest niedozwolone. Nie zostanie wygenerowany żaden błąd dotyczący bezpieczeństwa. Wszystkie pliki skryptu, które uruchamiane są w obszarze izolowanym aplikacji, muszą być zainstalowane w katalogu aplikacji. Aby użyć zewnętrznych skryptów na stronie, należy odwzorować stronę w innym obszarze izolowanym. Patrz Ładowanie treści aplikacji do nieaplikacyjnego obszaru izolowanego.

document.write() i document.writeln()

Wywołania metod document.write() lub document.writeln() są ignorowane po obsłużeniu zdarzenia load strony. Nie zostanie wygenerowany żaden błąd dotyczący bezpieczeństwa. Alternatywnym rozwiązaniem jest załadowanie nowego pliku lub zastąpienie treści dokumentu przy pomocy technik manipulowania DOM.

Synchroniczne XMLHttpRequests przed zdarzeniem load lub w czasie działania modułu obsługi zdarzenia load

Synchroniczne XMLHttpRequests zainicjowane przed zdarzeniem load strony lub w czasie działania modułu obsługi zdarzeń load nie zwracają żadnej treści. Asynchroniczne XMLHttpRequests można zainicjować, ale nie zwrócą żadnej treści dopóki nie zostanie zakończone zdarzenie load. Po obsłużeniu zdarzenia load synchroniczne XMLHttpRequests działają zwyczajnie.

Dynamicznie utworzone elementy skryptu

Dynamicznie utworzone elementy skryptu, np. elementy utworzone z właściwością innerHTML lub za pomocą metody document.createElement(), są ignorowane.