Zabezpieczenia HTML w środowisku Adobe AIR

Adobe AIR 1.0 i starsze wersje

W tym temacie opisano architekturę zabezpieczeń HTML w środowisku AIR, a także sposoby używania obiektów iFrame i Frame oraz mostu obszaru izolowanego w celu konfigurowania aplikacji opartych na standardzie HTML i bezpiecznego integrowania zawartości HTML w aplikacjach opartych na standardzie SWF.

Środowisko wykonawcze wymusza reguły i udostępnia mechanizmy przeznaczone dla wzmacniania słabych punktów zabezpieczeń w językach HTML i JavaScript. Te same reguły są wprowadzane niezależnie od tego, czy aplikacja jest napisana w kodzie JavaScript lub czy treść HTML i JavaScript została załadowana do aplikacji SWF. Treść w obszarze izolowanym aplikacji i nieaplikacyjnym bezpiecznym obszarze izolowanym ma różne uprawnienia. Podczas wczytywania zawartości obiektu iFrame lub Frame środowisko wykonawcze udostępnia bezpieczny most obszaru izolowanego , dzięki któremu zawartość obiektu iFrame lub Frame może komunikować się z zawartością obszaru izolowanego aplikacji.

Zestaw SDK środowiska AIR udostępnia trzy klasy służące do renderowania zawartości HTML.

Klasa HTMLLoader oferuje ścisłą integrację między kodem JavaScript i interfejsami API środowiska AIR.

Klasa StageWebView służy do renderowania zawartości HTML i oferuje bardzo ograniczoną integrację z aplikacją AIR, w której znajduje się ta zawartość. Zawartość wczytana przez klasę StageWebView nigdy nie jest umieszczana w obszarze izolowanym aplikacji i nie może uzyskiwać dostępu do danych ani wywoływać funkcji aplikacji AIR, w której się znajduje. Na platformach (komputerach) stacjonarnych klasa StageWebView korzysta z mechanizmu obsługi zawartości HTML wbudowanego w środowisko AIR. Tego mechanizmu używa także klasa HTMLLoader. Na platformach (urządzeniach) przenośnych klasa StageWebView używa elementu sterującego udostępnianego przez system operacyjny na potrzeby obsługi zawartości HTML. Z tego powodu na platformach przenośnych kwestie dotyczące zabezpieczeń i zagrożeń związanych z klasą StageWebView są takie same jak te związane z przeglądarką internetową systemu.

Klasa TextField może wyświetlać ciągi tekstu HTML. Klasa ta nie pozwala wykonywać kodu JavaScript, ale tekst może zawierać łącza i obrazy wczytane z zewnątrz.

Więcej informacji zawiera sekcja Unikanie błędów JavaScript związanych z zabezpieczeniami .

Przegląd konfigurowania aplikacji opartej na formacie HTML

Ramki i ramki pływające stanowią wygodny sposób organizowania treści HTML w AIR. Ramki umożliwiają zachowanie spójności danych i bezpieczną pracę z treścią zdalną.

HTML w aplikacji AIR zachowuje normalną nawigację opartą na stronach, dlatego środowisko HTML zostaje całkowicie odświeżone, jeśli z górnej ramki treści HTML nastąpi przejście do innej strony. Ramki i ramki pływające mogą być używane do zachowywania spójności danych w AIR, podobnie jak w aplikacji sieci Web działającej w przeglądarce. Główne obiekty aplikacji należy zdefiniować w najwyższej ramce — te obiekty pozostaną niezmienione do czasu przejścia w ramce do następnej strony. W celu wyświetlania przejściowych sekcji aplikacji należy używać ramek i ramek pływających. (Istnieją różne sposoby na zachowanie spójności danych, które mogą być używane razem z ramkami oraz oprócz ramek. Należą do nich pliki cookie, lokalne obiekty współużytkowane, lokalny obszar zapisu plików, magazyn plików zaszyfrowanych oraz lokalny obszar zapisu bazy danych).

Ponieważ kod HTML w środowisku AIR zachowuje w swój standardowy, pośredni charakter między kodem wykonywalnym a danymi, środowisko AIR wstawia treść w górnej ramce HTML w obszarze izolowanym aplikacji. Po zdarzeniu load strony środowisko AIR ogranicza wszystkie operacje (np. eval() ), które mogą konwertować ciąg znaków tekstu na wykonywalny obiekt. To ograniczenie jest wymuszane nawet wówczas, gdy aplikacja nie ładuje treści zdalnej. Aby umożliwić treści HTML wykonanie tych ograniczonych operacji, należy użyć ramek lub ramek pływających w celu umieszczenia treści w nieaplikacyjnym obszarze izolowanym. (Uruchomienie treści w ramce podrzędnej z obszaru izolowanego może być konieczne, jeśli używane są niektóre architektury aplikacji JavaScript, które odwołują się do funkcji eval() ). Pełną listę ograniczeń JavaScript w obszarze izolowanym aplikacji zawiera sekcja Ograniczenia kodu dotyczące treści różnych obszarów izolowanych .

HTML w AIR zachowuje zdolność ładowania zdalnej, prawdopodobnie niebezpiecznej treści, dlatego środowisko AIR wymusza strategię jednego źródła, która zapobiega interakcjom między treścią jednej domeny z treścią innej domeny. Aby umożliwić interakcje między treścią jednej domeny z treścią drugiej domeny, należy skonfigurować most, który będzie służył jako połączenie między ramką nadrzędną i podrzędną.

Konfigurowanie relacji nadrzędny-podrzędny dla obszarów izolowanych

Środowisko AIR dodaje atrybuty sandboxRoot i documentRoot do elementów ramek i ramek pływających HTML. Te atrybuty umożliwiają traktowanie treści aplikacji w taki sposób, jakby pochodziła z innej domeny:

Atrybut

Opis

sandboxRoot

Adres URL przeznaczony do określenia obszaru izolowanego i domeny, do której należy wprowadzić treść ramki. Należy użyć schematów URL: file: , http: lub https: .

documentRoot

Adres URL, z którego ładowana jest treść ramki. Należy użyć schematów URL: file: , app: lub app-storage: .

Poniższy przykład odwzorowuje treść zainstalowaną w podkatalogu sandbox aplikacji w celu uruchomienia w zdalnym obszarze izolowanym oraz domenie www.example.com:

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

Konfigurowanie mostu między ramkami nadrzędnymi i podrzędnymi w różnych obszarach izolowanych i domenach

Środowisko AIR dodaje właściwości childSandboxBridge i parentSandboxBridge do obiektu window dowolnej ramki podrzędnej. Te właściwości umożliwiają definiowanie mostów, które służą jako połączenia między ramką podrzędną i nadrzędną. Każdy most jest jednokierunkowy:

childSandboxBridge — właściwość childSandboxBridge umożliwia ramce podrzędnej zaprezentowanie interfejsu do treści ramki nadrzędnej. W celu zaprezentowania interfejsu należy ustawić dla właściwości childSandbox funkcję lub obiekt ramki podrzędnej. Następnie można uzyskać dostęp do obiektu lub funkcji z treści ramki nadrzędnej. Poniższy przykład przedstawia, w jaki sposób skrypt uruchomiony w ramce podrzędnej może prezentować obiekt zawierający funkcję i właściwość dla jej obiektu nadrzędnego:

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

Jeśli treść podrzędna znajduje się w ramce pływającej, do której przypisano id "child" , wówczas można uzyskać dostęp do interfejsu z treści nadrzędnej poprzez odczytanie właściwości childSandboxBridge ramki:

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

parentSandboxBridge — właściwość parentSandboxBridge umożliwia ramce nadrzędnej zaprezentowanie interfejsu do treści ramki podrzędnej. W celu zaprezentowania interfejsu należy ustawić właściwość parentSandbox ramki podrzędnej na funkcję lub obiekt ramki nadrzędnej. Następnie można uzyskać dostęp do obiektu lub funkcji z treści ramki podrzędnej. Poniższy przykład przedstawia, w jaki sposób skrypt uruchomiony w ramce nadrzędnej może prezentować obiekt zawierający funkcję zapisu obiektowi podrzędnemu:

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

Za pomocą tego interfejsu treść ramki podrzędnej może zapisywać tekst do pliku o nazwie save.txt. Jednak treść nie będzie miała dostępu do systemu plików. W przypadku ogólnym treść aplikacji powinna prezentować innym obszarom izolowanym interfejs o najmniejszych ograniczeniach. Zawartość elementu potomnego może wywołać funkcję save w następujący sposób:

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

Jeśli treść elementu podrzędnego podejmie próbę ustawienia właściwości obiektu parentSandboxBridge , wówczas środowisko wykonawcze zgłasza wyjątek SecurityError. Jeśli treść elementu nadrzędnego podejmie próbę ustawienia właściwości obiektu childSandboxBridge , wówczas środowisko wykonawcze zgłasza wyjątek SecurityError.

Ograniczenia kodu dotyczące treści różnych obszarów izolowanych

We wstępie do sekcji Zabezpieczenia HTML w środowisku Adobe AIR opisano, że środowisko wykonawcze wymusza reguły i udostępnia mechanizmy przeciwdziałania możliwym słabym punktom zabezpieczeń w HTML i JavaScript. W niniejszym temacie przedstawiono te ograniczenia. Jeśli kod podejmuje próbę wywołania ograniczonych interfejsów API, wówczas środowisko wykonawcze zgłasza błąd z komunikatem „Naruszenie zabezpieczeń środowiska wykonawczego Adobe AIR dla kodu JavaScript w obszarze izolowanym zabezpieczeń aplikacji”.

Więcej informacji zawiera sekcja Unikanie błędów JavaScript związanych z zabezpieczeniami .

Ograniczenia dotyczące korzystania z funkcji eval() JavaScript oraz z innych technik

Dla treści HTML w bezpiecznym obszarze izolowanym aplikacji obowiązują ograniczenia dotyczące korzystania z interfejsów API, które mogą dynamicznie przekształcać ciągi znaków na kod wykonywalny — po załadowaniu kodu (po wywołaniu zdarzenia onload elementu body oraz po zakończeniu działania funkcji modułu obsługi onload ). Takie rozwiązanie zapobiega przypadkowemu wstrzyknięciu i wykonaniu kodu ze źródeł nieaplikacyjnych (np. potencjalnie niebezpiecznych domen sieciowych).

Na przykład: jeśli aplikacja korzysta z danych w postaci ciągu znaków ze źródła zdalnego w celu zapisywania we właściwości innerHTML elementu DOM, wówczas ciąg znaków może zawierać kod wykonywalny(JavaScript), który może wykonywać niebezpieczne operacje. Jednak podczas ładowania treści nie ma zagrożeń związanych z wstawianiem zdalnych ciągów znaków do elementu DOM.

Jedno ograniczenie dotyczy korzystania z funkcji eval() JavaScript. Po załadowaniu kodu do obszaru izolowanego aplikacji i przetworzeniu modułu obsługi zdarzenia onload możliwe jest korzystanie z funkcji eval() w ograniczonym zakresie. Poniższe reguły dotyczą stosowania funkcji eval() po załadowaniu kodu z obszaru izolowanego aplikacji:

  • Dozwolone są wyjątki obejmujące literały. Na przykład:

    eval("null"); 
    eval("3 + .14"); 
    eval("'foo'");
  • Dozwolone są literały obiektów, jak poniżej:

    { prop1: val1, prop2: val2 }
  • Stosowanie literałów obiektów set/get jest zabronione , jak poniżej:

    { get prop1() { ... }, set prop1(v) { ... } }
  • Dozwolone są literały tablic, jak poniżej:

    [ val1, val2, val3 ]
  • Wyrażenia zawierające odczyty właściwości są zabronione , jak poniżej:

    a.b.c
  • Wywołanie funkcji jest zabronione .

  • Definicje funkcji są zabronione .

  • Ustawienie właściwości jest zabronione .

  • Literały funkcji są zabronione .

Jednak podczas ładowania kodu przed zdarzeniem onload oraz podczas działania funkcji modułu obsługi zdarzeń onload te ograniczenia nie dotyczą treści bezpiecznego obszaru izolowanego aplikacji.

Na przykład: po załadowaniu kodu wykonanie poniższego kodu powoduje wyjątek w środowisku wykonawczym:

eval("alert(44)"); 
eval("myFunction(44)"); 
eval("NativeApplication.applicationID");

Kod wygenerowany dynamicznie, np. podczas wywoływania funkcji eval() może spowodować zagrożenie, jeśli uzyska dostęp do obszaru izolowanego aplikacji. Przykład: aplikacja może przypadkowo wykonać ciąg znaków załadowany z domeny sieciowej, a ten ciąg znaków może zawierać złośliwy kod. Może to być na przykład kod, który spowoduje usunięcie lub modyfikację plików w komputerze. Lub może to być kod, który będzie zgłaszał treść pliku lokalnego do niezaufanej domeny sieciowej.

Sposoby dynamicznego generowania kodu:

  • Wywołanie funkcji eval() .

  • Użycie właściwości innerHTML lub funkcji DOM w celu wstawienia znaczników script, które powodują ładowanie skryptu poza katalogiem aplikacji.

  • Użycie właściwości innerHTML lub funkcji DOM w celu wstawienia znaczników script zawierających kod wbudowany (zamiast ładowania skryptu za pomocą atrybutu src ).

  • Ustawienie atrybutu src dla znaczników script w celu załadowania pliku JavaScript, który znajduje się na zewnątrz katalogu aplikacji.

  • Użycie schematu URL javascript (jak w href="javascript:alert('Test')" ).

  • Użycie funkcji setInterval() lub setTimout() , w której pierwszy parametr (definiujący funkcję, która działa asynchronicznie) jest ciągiem znaków (wartość wynikowa), a nie nazwą funkcji (jak w przykładzie: setTimeout('x = 4', 1000) ).

  • Wywołanie metody document.write() lub document.writeln() .

Kod w obszarze izolowanym aplikacji może korzystać z tych metod tylko podczas ładowania treści.

Te ograniczenia nie zapobiegają stosowania funkcji eval() z literałami obiektów JSON. Dzięki temu treść aplikacji może pracować z biblioteką JavaScript JSON. Niedozwolone jest natomiast korzystanie z przeciążonego kodu JSON (z podprogramami obsługi zdarzeń).

W przypadku innych struktur Ajax i bibliotek kodu JavaScript należy upewnić się, czy kod w strukturze lub bibliotece działa zgodnie z tymi samymi ograniczeniami, które dotyczą kodu generowanego w sposób dynamiczny. Jeśli nie, należy dołączyć treść, która korzysta ze struktury lub biblioteki, do nieaplikacyjnego obszaru izolowanego. Szczegółowe informacje zawierają rozdziały Ograniczenia obowiązujące dla kodu JavaScript w środowisku AIR oraz Treść aplikacyjna i nieaplikacyjna odwołująca się do skryptów . Firma Adobe udostępnia listę środowisk Ajax, które obsługują bezpieczne obszary izolowane aplikacji, na stronie http://www.adobe.com/products/air/develop/ajax/features/ .

Treść JavaScript — w odróżnieniu od treści obszaru izolowanego aplikacji — w nieaplikacyjnym obszarze izolowanym może wywoływać funkcję eval() w celu wykonywania kodu wygenerowanego w sposób dynamiczny w dowolnym czasie.

Ograniczenia dostępu do interfejsów API AIR (dla nieaplikacyjnych obszarów izolowanych)

Kod JavaScript w nieaplikacyjnym obszarze izolowanym nie ma dostępu do obiektu window.runtime i dlatego kod nie może uruchamiać interfejsów API AIR. Jeśli treść nieaplikacyjnego obszaru izolowanego wywoła poniższy kod, aplikacja zgłosi wyjątek TypeError:

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

Wyjątek ma typ TypeError (wartość niezdefiniowana), ponieważ treść nieaplikacyjnego obszaru izolowanego nie rozpoznaje obiektu window.runtime , dlatego jest on widoczny jako wartość niezdefiniowana.

Za pośrednictwem mostu można zaprezentować funkcje środowiska wykonawczego dla treści nieaplikacyjnego obszaru izolowanego. Szczegółowe informacje zawiera rozdział Treść aplikacyjna i nieaplikacyjna odwołująca się do skryptów .

Ograniczenia dotyczące korzystania z wywołań XMLHttpRequest

Treść HTML w obszarze izolowanym aplikacji nie może korzystać z synchronicznych metod XMLHttpRequest w celu ładowania danych spoza obszaru izolowanego aplikacji podczas ładowania treści HTML oraz podczas zdarzenia onLoad .

Domyślnie treść HTML w nieaplikacyjnych obszarach izolowanych nie ma możliwości korzystania z obiektu XMLHttpRequest JavaScript w celu ładowania danych z domen innych niż domena wywołująca żądanie. Znacznik frame lub iframe może zawierać atrybut allowcrosscomainxhr . Ustawienie tego atrybutu na wartość inną niż null umożliwia zawartości obiektu Frame lub iFrame korzystanie z obiektu XMLHttpRequest języka JavaScript w celu wczytywania danych z domen innych niż domena kodu wywołującego żądanie.

<iframe id="UI" 
    src="http://example.com/ui.html" 
    sandboxRoot="http://example.com/" 
    allowcrossDomainxhr="true" 
    documentRoot="app:/"> 
</iframe>

Więcej informacji zawiera sekcja Treść odwołująca się do skryptów w różnych domenach .

Ograniczenia dotyczące ładowania elementów CSS, ramek, ramek pływających i img (dla treści nieaplikacyjnych obszarów izolowanych)

Treść HTML w zdalnych (sieciowych) obszarach izolowanych może ładować tylko treść CSS, frame , iframe i img ze zdalnych obszarów izolowanych (z sieciowych adresów URL).

Treść HTML w lokalnym obszarze izolowanym z systemem plików, lokalnym obszarze izolowanym z obsługą sieci lub lokalnym zaufanym obszarze izolowanym może ładować tylko treść CSS, ramek, ramek pływających i img z lokalnych obszarów izolowanych (nie z aplikacyjnych ani zdalnych obszarów izolowanych).

Ograniczenia dotyczące wywoływania metody window.open() JavaScript

Jeśli okno utworzone poprzez wywołanie metody window.open() JavaScript wyświetla treść nieaplikacyjnego obszaru izolowanego, wówczas tytuł okna rozpoczyna się od tytułu głównego okna (uruchamiania), po którym następuje znak dwukropka. Za pomocą kodu nie można przesunąć tej części tytułu okna poza ekran.

Treść nieaplikacyjnych obszarów izolowanych może wywoływać z powodzeniem metodę window.open() JavaScript w odpowiedzi na zdarzenie wywołane przez interakcję z myszą lub klawiaturą. Dzięki temu treść nieaplikacyjna nie może tworzyć okien, które mogłyby zostać wykorzystane oszukańczo (np. w atakach typu phishing). Ponadto moduł obsługi zdarzeń myszy lub klawiatury nie może ustawiać wykonywania metody window.open() po opóźnieniu (np. poprzez wywołanie funkcji setTimeout() ).

Treść w zdalnych (sieciowych) obszarach izolowanych może korzystać z metody window.open() wyłącznie w celu otwierania treści w zdalnych (sieciowych) obszarach izolowanych. Nie może korzystać z metody window.open() w celu otwierania treści z obszarów izolowanych aplikacji lub lokalnych obszarów izolowanych.

Treść lokalnych obszarów izolowanych z systemem plików, lokalnych obszarów izolowanych z obsługą sieci i lokalnych zaufanych obszarów izolowanych (patrz Obszary izolowane ) może korzystać z metody window.open() tylko w celu otwierania treści w lokalnych obszarach izolowanych. Nie może korzystać z metody window.open() w celu otwierania treści obszarów izolowanych aplikacji ani zdalnych obszarów izolowanych.

Błędy podczas wywoływania kodu ograniczonego

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: „Naruszenie zabezpieczeń środowiska wykonawczego Adobe AIR dla kodu JavaScript w obszarze izolowanym zabezpieczeń aplikacji”.

Więcej informacji zawiera sekcja Unikanie błędów JavaScript związanych z zabezpieczeniami .

Zabezpieczenie obszaru izolowanego podczas ładowania treści HTML z ciągu znaków

Metoda loadString() klasy HTMLLoader umożliwia tworzenie treści HTML w czasie wykonywania. Jednak dane używane jako treść HTML mogą być uszkodzone, jeśli dane są ładowane z niebezpiecznego źródła z sieci Internet. Z tego względu domyślnie treść HTML utworzona za pomocą metody loadString() nie jest umieszczana w obszarze izolowanym aplikacji i nie ma dostępu do interfejsów API środowiska AIR. Jednak użytkownik może ustawić właściwość placeLoadStringContentInApplicationSandbox obiektu HTMLLoader na wartość true, aby umieścić treść HTML utworzoną za pomocą metody loadString() w obszarze izolowanym aplikacji. Więcej informacji zawiera sekcja Wczytywanie zawartości HTML z ciągu znaków .