laupäev, 17. oktoober 2009

Cross domain JavaScript

Ülidselt on cross-domain JavaScript brauserites rangelt keelatud. See tähendab, et ei ole võimalik teha AJAX päringuid võõrasse domeeni (st. domeeni, mis on erinev lehe domeenist, kust päring esitati, näiteks www.neti.ee ei saa teha AJAX päringut aadressile www.delfi.ee) ning samuti ei ole võimalik JavaScriptil ligi pääseda võõrast domeenist tulevale teise freimi või akna sisule.

Juhul kui domeenid on samad, pole freimide (sh. ka iframe ning brauseri teised aknad) puhul mingit probleemi - teise freimi sisu on kättesaadav sama lihtsalt nagu window.document DOM puu. window.document asemel tuleb kasutada lihtsalt vastavale freimile viitavale objektile. Iframe saab põhifreimi kätte objektist parent ning aken, mis on avatud teise akna poolt, saab avaja kätte objektist window.opener.

Juhul kui põhidomeen on sama, aga alamdomeen on erinev, näiteks ühes freimis on avatud leht aadressilt www1.neti.ee ja teises freimis on avatud www2.neti.ee, saavad freimid omavahel suhelda, kui mõlemad muudavad ära document.domain väärtuse põhidomeeni vastu.

Põhifreim (www1.neti.ee):
document.domain = 'neti.ee';
abc = 123;

Iframe (www2.neti.ee):
document.domain = 'neti.ee';
alert(parent.abc); //123

Keerulisem aga on lugu juhul, kui erinevad freimid asuvad täiesti eri domeenidel, näiteks aadressidel teenus1.com ning teenus2.com. Siiani praktiline lahendus puudus, kuid uutes HTML5 toega brauserites (näiteks alates Firefox 3.0 ning Internet Explorer 8) on probleemi lahendamiseks võimalik kasutada messaging API't.

Töötab asi järgmiselt - freim, kes tahab saata teisele freimile mingit infot, käivitab selle jaoks vastava freimi objektis postMessage meetodi, mis edastab info adressaadini. Adressaat ise aga peab sõnumite kättesaamiseks seadma üles vastava sündmusehalduri (window.onmessage).

Juhul kui sündmuse haldajale laekub teisest freimist sõnum peaks see kontrollima, kas info tuleb usaldusväärsest allikast ning seejärel saab teha saadud infoga, mida vaja.

Sisuliselt võib öelda, et turvakontroll on lükatud brauserist skripti poolele. Skript ise vastutab, et see info (mis tuleb sisse alati stringi kujul) kõlbab töötlemiseks või mitte.

Sõnumi saatmiseks tuleb kasutada postMessage meetodit:

parent.postMessage(message, targetOrigin);

message on saadetav sõnum stringi kujul.
targetOrigin - string, mis määrab ära lubatud vastuvõtja. Lubatud kuju on protokoll://domeen[:port]. Port on vaja määrata vaid juhul, kui see ei ole sama mis protokolli vaikimis port (http:80, https:443). Võimalik on kasutada ka kuju "*",  sellisel juhul saavad sõnumi kõik aknad.

Sõnumi kättesaamiseks adressaadi poolt tuleb seada üles vastav sündmus - onmessage.

window.onmessage = function(e){
    e.source; // objekt, mis viitab sõnumit saatvale freimile
    e.origin; // string, mis sisaldab endas saatja domeeni kujul protokoll://domeen[:port]
    e.data; // vastuvõetud sõnum stringi kujul
}

Kuigi sõnumi saatja kontroll pole kohustuslik, samuti võib sõnumit saata "broadcast'ina", kasutades vastuvõtjana stringi "*", on soovitatav kontrollida nii sõnumi saajat, kui saatjat. Ja seda seetõttu, et kolmandad osapooled ei saaks midagi kurja korda saata.

Näiteks eeldame, et stringi kujul transporditakse JSON koodi, mis käivitatakse vastuvõtja poolt eval käsuga.

window.onmessage = function(e){
    data = eval(e.data);
}

Juhul kui saatjaks on pahalane, võib e.data sisaldada endas näiteks mõnda funktsiooni, mis tõstab kõrvale kasutaja hetke sessiooni või veebipõhise e-posti kliendi puhul näiteks suunab kasutaja e-posti aadressi pahalase aadressile. Sellest, aga mida kõike paha sarnasel viisil teha annab (meenutagem näiteks Orkuti viiruseid), kirjutan juba mõni teine kord.

Lingid:
window.postMessage Mozilla Developers saidil
window.postMessage dokumentatsioon MSDN saidil

Kommentaare ei ole: