You are here: TUTWiki>Tietoturva/Tutkielmat>Tutkielmat?>HTML5CORS

TTY / Tietoturvallisuuden jatkokurssi / Harjoitustyö 2012

Tapio Linnimäki

HTML5: Cross Origin Resource Sharing

Johdanto

HTML5 sisältää paljon uusia ominaisuuksia web-kehittäjän käytettäväksi, kuten uusia tageja ja attribuutteja. Merkkauksen lisäksi HTML5:n mukana tulee myös muita uusia tekniikoita ja ominaisuuksia. Tässä työssä tarkastelun kohteena on Cross Origin Resource Sharing -tekniikka (CORS), joka mahdollistaa yhdeltä palvelimelta ladatun skriptin pääsyn resursseihin toisella palvelimella, jolla on eri domain [4]. Aikaisemmin selainten valvoma saman alkuperän (same origin) turvarajoitus esti tämän, mutta koska tarve tällaisille asiakaspuolen cross-origin pyynnöille on suuri, on CORS-toiminto kehitetty mahdollistamaan tämä ottaen tietoturvallisuus huomioon. Tässä työssä esitellään mikä same-origin turvarajoitus on, jonka jälkeen perehdytään sekä asiakas- että palvelinpuolella siihen, kuinka CORS toimii ja mitä tietoturva-asioita pitää ottaa huomioon sitä käytettäessä, kun selainpuolen ohjelmointikielenä on JavaScript.

Same-origin politiikka ja JavaScript

JavaScriptissä XMLHttpRequest-olio tarjoaa rajapinnan HTTP ja HTTPS kyselyjen tekemiseen selaimesta suoraan web-palvelimelle ja vastausdatan lataamisen suoraan takaisin skriptiin. Tekniikkaa käytetään dynaamisten verkkosivujen toteutukseen. Palvelimen ja selaimen välillä pystytään välittämään dataa taustalla sivun latauksen jälkeenkin ilman häiriötä käyttäjälle. Hyötynä on esimerkiksi, että sivua pystytään päivittämään ilman sivun uudelleenlatausta.

Ennen HTML5:ttä saman alkuperän (same origin) -turvarajoitus rajoitti HTTP-pyyntöjen tekemisen asiakaspuolella JavaScriptillä XMLHttpRequest-oliota käyttäen vain saman sivuston eli domainin sisälle. Näin ollen yhdeltä sivustolta ladatulla JavaScript-ohjelmalla ei siis ollut pääsyä muiden sivustojen tai edes saman sivuston alidomainien resursseihin, ilman jonkinlaista rajoituksen kiertoa, kuten esimerkiksi kyselyn kierrätys välityspalvelimen kautta. Kaksi eri resurssia tulkitaan olevan samaa alkuperää vain, jos niillä on sama protokolla, sama domain-nimi ja sama porttinumero. Vain jos nämä ehdot täyttyvät on pääsy sallittu. Seuraavassa taulukossa on esitetty esimerkki saman alkuperän vertailusta, kun vertailukohteena on URL http://www.example.com/dir/page.html. [2.]

Vertailtava URL Tulos Syy
http://www.example.com/dir/page.htm Pääsy sallittu Sama protokolla, domain-nimi ja porttinumero
http://www.example.com/dir2/other.html Pääsy sallittu Sama protokolla, domain-nimi ja porttinumero
http://www.example.com:81/dir/other.html Pääsy estetty Eri porttinumero (81)
https://www.example.com/dir/other.html Pääsy estetty Eri protokolla (HTTPS)
http://en.example.com/dir/other.html Pääsy estetty Eri domain (ali-domain en)
http://example.com/dir/other.html Pääsy estetty Eri domain (Täytyy olla täysin sama)
http://v2.www.example.com/dir/other.html Pääsy estetty Eri domain (Täytyy olla täysin sama)

Syy tälle rajoitukselle on tietoturva. XMLHttpRequest-pyyntö palvelimelle tehtäessä lähetetään myös kyseisen palvelimen selaimeen tallentamat käyttäjän evästeet, kuten istuntotiedot, pyynnön mukana. Tästä johtuen ilman same-origin rajoitusta voisi haitalliselta sivustolta ladatulla JavaScript-koodilla olla mahdollista tehdä uhrille etuoikeutettuja pyyntöjä hyökkäyksen kohteena olevaan palveluun, jos hän on sinne samaan aikaan kirjautuneena. Esimerkiksi voisi olla mahdollista saada ladattua luottamuksellisia tietoja, jotka skripti edelleen välittäisi hyökkääjän palvelimelle.

Tämä turvallisuusmekanismi kuitenkin rajoittaa myös täysin asiallista eri sivustojen välistä kommunikaatiota JavaScriptillä. Esimerkiksi kaksi eri verkkopalvelua saattavat haluta sallia toisilleen pääsyn tiettyihin resursseihin palvelimillaan suoraan JavaScript-koodista. Ongelmia aiheutuu myös, jos samalla sivustolla on käytössä useita eri ali-domaineja, kuten taulukosta huomataan [2]. Tällaiselle eri alkuperien väliselle kommunikaatiolle on suuri tarve ja erilaiset rajoituksen kiertämisen tekniikat tuovat taas omat ongelmansa. Tästä johtuen HTML5 tuo uuden Cross Origin Resource Sharing -ominaisuuden (CORS), jolla pyritään sallimaan eriävien alkuperien pyynnöt turvallisesti lieventämällä same origin -rajoitusta.

Cross Origin Resource Sharing (CORS)

Toiminta

Selaimesta on ennenkin ollut mahdollista tehdä cross-origin pyyntöjä määrittämällä eri alkuperän resurssi esimerkiksi IMG-tagissa. Erona näissä pyynnöissä on kuitenkin se, ettei asiakaspuolen skripteillä ole pääsyä vastauksena annetun resurssin sisältöön. CORS määrittelee kuinka kommunikointi selaimen ja palvelimen välillä tulee tapahtua, kun skriptistä tehdään eriävän alkuperän pyyntöjä. CORS-tekniikan käyttäminen vaatii koordinaatiota palvelimen ja selaimen välillä. Periaatteessa tämä tapahtuu käyttämällä HTTP-pyynnöissä ja vastauksissa uusia CORS-spesifejä otsikkokenttiä ja JavaScriptin XMLHttpRequest-olion [6] uudella versiolla 2, joka on käytettävissä Chrome, Firefox, Opera ja Safari selaimissa. Internet Explorer -selaimessa käytetään XMLHTttpRequest-olion sijaan sen omaa XDomainRequest-oliota, joka kuitenkin toimii hyvin pitkälti samaan tapaan. [3.] Tässä tarkastellaan CORS-ominaisuutta käyttäen XMLHttpRequest oliota.

CORS-pyynnöt jaetaan monimutkaisiin ja yksinkertaisiin tapauksiin, joiden suoritustapa eroaa hiukan. Monimutkaisella pyynnöllä tarkoitetaan pyyntöä, jossa käytetään jotain muuta HTTP-metodia, kuin GET, HEAD tai POST, tai se sisältää mukautettuja (ei-standardeja) otsikkokenttiä. Monimutkaisille CORS-pyynnöille selain tekee sisäisesti kaksi eri pyyntöä. Ensin selain tekee ns. preflight-pyynnön käyttäen OPTIONS HTTP-metodia, jolla vain tarkistetaan salliiko palvelin kyseessä olevan tyyppisen pyynnön. Vasta siihen vastauksen saatuaan selain lähettää itse oikean pyynnön. XMLHttpRequest-olion käyttäjälle tämä näyttää kuitenkin vain yhdeltä pyynnöltä. Yksinkertaisissa pyynnöissä tiedon välitys tapahtuu yhdellä pyyntö-vastaus parilla ilman preflight esikyselyä. Seuraavassa kuvassa on havainnollistettu CORS-pyynnön suoritusvaiheita. [3.]

CORS-pyyntö

Selain liittää automaattisesti XMLHttpRequest-olion send()-metodia käyttäen tehtyyn CORS-pyyntöön seuraavat HTTP-otsikkokentät [3]:
  • Origin: Origin-kenttä on aina mukana CORS-pynnöissä. Kentässä on kerrottu alkuperä (protokolla, domain, portti), josta pyyntö on lähtöisin. Tätä ei käyttäjä pysty kontrolloimaan. Esimerkiksi http://www.esimerkki.net
  • Access-Control-Request-Method: Preflight-pyynnössä käytettävä otsikkokenttä. Kentällä määritellään mitä http-metodia oikeassa pyynnössä käytetään.
  • Access-Control-Request-Headers: Preflight-pyynnössä käytettävä valinnainen otsikkokenttä, jossa on listattu oikeassa pyynnössä mukana olevat mukautetut HTTP-otsikkokentät, jos niitä on.

Jotta CORS-ominaisuutta voidaan käyttää täytyy palvelinpuoli konfiguroida käyttämään HTTP-vastauksissaan CORS-otsikkokenttiä. Palvelin voi päättää CORS-pyynnön hyväksynnästä ja määrittää CORS-pyyntöihin liittyviä asetuksia käyttämällä vastauksessaan selaimelle seuraavia otsikkokenttiä [3]:
  • Access-Control-Allow-Origin: Alkuperät, joista palvelin sallii CORS-pyynnöt kyseiseen URL-osoitteeseen. Aina pakollinen kenttä valideissa CORS-vastauksissa. Voi olla myös *-jokerimerkki, jolloin sallitaan pyynnöt kaikista alkuperistä. Jos tämä kenttä on jätetty pois tai alkuperät ei täsmää, ei pyyntöä sallita.
  • Access-Control-Allow-Credentials: Tulisiko pyyntöjen mukana välittää valtuustietoja, kuten evästeitä. Jos valtuustiedot tulee lähettää pyynnön mukana, asetetaan arvoksi true, muutoin kenttä jätetään pois. Sekä preflight että yksinkertaisissa pyynnöissä.
  • Access-Control-Expose-Headers: Lista niistä vastauksen otsikkokentistä, joihin ei ole oletuksena pääsyä asiakaspäässä, mutta halutaan sallia pääsy. CORS-pyynnöissä oletuksena pääsy on asiakaspäässä sallittu vain otsikkokenttiin Cache-Control, Content-Language, Content-Type, Expires, Last-Modified ja Pragma.
  • Access-Control-Allow-Methods: Preflight-vastauksissa käytettävä otsikkokenttä. Lista HTTP-metodeista, joiden käytön palvelin sallii CORS-pyynnöissä.
  • Access-Control-Allow-Headers: Preflight-vastauksissa käytettävä otsikkokenttä. Lista pyynnöissä sallituista mukautetuista otsikkokentistä.
  • Access-Control-Max-Age: Valinnainen preflight-kyselyissä käytetty kenttä, jossa voidaan määrittää kuinka kauan vastausta preflight-kyselyyn säilytetään selaimen välimuistissa. Tämä on tehokkuuden kannalta hyödyllistä, jos selain tekee useita pyyntöjä samaan kohteeseen, koska silloin ei tarvita aina uutta preflight-pyyntöä ennen varsinaista oikeata pyyntöä.

Tietoturva

CORS-pyynnöissä ei lähetetä oletuksena pyynnön mukana valtuustietoja, kuten evästeitä, HTTP-autentikointitietoja tai asiakaspuolen SSL-sertifikaattia. Tämä olisi tietoturvariski, kuten same-origin rajoitteen esittelyssä tuli ilmi. Jos nämä halutaan lähettää pyynnön mukana, täytyy erikseen asettaa asiakaspäässä XMLHttpRequest-olion withCredentials-ominaisuus päälle ennen pyyntöä. Palvelinpäässä CORS-pyynnön kohteena oleva palvelin voi asettaa salliiko evästeitä tai muita valtuustietoja sisältäviä CORS-pyyntöjä kyseisestä alkuperästä käyttämällä Access-Control-Allow-Credentials HTTP-otsikkokenttää. Tämän otsikkokentän käytön kanssa tulee olla varovainen ja sallia valtuustietoja sisältävät pyynnöt vain erittäin luotetuille alkuperille, jos on varma, että niitä tarvitaan. [3.]

Kun selainpuolella XMLHttpRequest-oliota käyttäen tehdään CORS-pyyntö, tulee varmistua, että kohde johon pyyntö tehdään on varmasti oikea ja luotettava. CORS ei itsessään mitenkään ota kantaa siihen, onko palvelimen pyyntöön vastauksena palauttama data turvallista. Jos siis CORS-pyynnön kohteena sattuu olemaan haitallista dataa palauttava palvelin, voi tämä antaa hyökkääjälle mahdollisuuden koodin injektointiin. Tästä syystä kannattaa XMLHttpRequest-oliolle välitettävä pyynnön kohteen URL validoida ja vastaanotettu data tarkastaa haitallisuuden varalta myös luotetuilta lähteiltä. [1; 5.]

Palvelinpuolella Access-Control-Allow-Origin otsikkokentän varomaton käyttö voi aiheuttaa tietoturvariskin. CORS-pyynnöt palvelun URL-osoitteisiin tulisi sallia vain niin suppealle joukolle luotettuja domaineja kuin mahdollista ja sallitut domainit tulisi määrittää sivu/resurssikohtaisesti. Erityisesti *-jokerimerkkiä kentän arvona tulee välttää, ellei kyseessä ole julkinen resurssi, sillä tämä sallisi kyseisen resurssin jakamisen minkä tahansa domainin kanssa. [1; 5.]

Preflight-kyselyn vastauksen välimuistissa säilyttämisen ajan määrittely liian pitkäksi Access-Control-Max-Age -otsikkokenttää käyttäen voi aiheuttaa turvallisuusuhkan. Vaikka CORS-pyyntöjen sallintapolitiikkaa palvelimella muutettaisiinkin noudattaisi selain silti vanhaa välimuistista saatavilla olevaa politiikkaa. [5.]

CORS-tekniikan käyttö voi olla haavoittuvaista otsikkokenttien väärentämiselle. Esimerkiksi selain lähettää jokaisen CORS-pyynnön mukana Origin-otsikkokentän, mutta hyökkääjä saattaa pystyä väärentämään tämän otsikkokentän arvon selaimen ulkopuolella. Tästä syystä pääsynvalvontaa ei pitäisi suorittaa pelkän Origin-otsikkokentän perustellaa, vaikka pyynnön alkuperä vaikuttaisikin sen perusteella luotettavalta. [1; 5.]

Yhteenveto

CORS-tekniikka tarjoaa kaivatun mahdollisuuden cross-origin pyyntöjen tekemiseen selaimelle ladatusta skriptistä, jota ennen rajoitti selainten valvoma same-origin turvarajoitus. Se on kompromissi turvallisuuden ja käytännöllisyyden välillä. CORS-tekniikan hyödyntäminen vaatii palvelinpuolen konfigurointia, jotta uudet HTTP-otsikkokentät saadaan otettua käyttöön pyynnöissä ja vastauksissa. Asiakaspuolella selainvalmistajat ovat vastuussa CORS-tekniikan selainpuolen implementoinnista. CORS-tekniikan käyttöön liittyy muutamia tietoturvariskejä, jotka web-sovellusten kehittäjän on ymmärrettävä ja pidettävä mielessä, jotta sovelluksen tietoturva ei vaarantuisi.

Lähteet

[1] OWASP, HTML5 Security Cheat Sheet, https://www.owasp.org/index.php/HTML5_Security_Cheat_Sheet

[2] W3C, Same origin policy http://www.w3.org/Security/wiki/Same_Origin_Policy

[3] Monsur Hossain, Using CORS, http://www.html5rocks.com/en/tutorials/cors/

[4] W3C, Cross-Origin Resource Sharing standardin työversio, http://www.w3.org/TR/cors/

[5] Andlabs, CORS security artikkeli, http://code.google.com/p/html5security/wiki/CrossOriginRequestSecurity

[6] W3C XMLHttpRequest Level 2, http://www.w3.org/TR/XMLHttpRequest/

SivuTiedotLaajennettu edit

Vaativuus Jatko
Valmius Valmis
Tyyppi Ydin
Luokitus Verkko
Mitä Useita
Miltä Useita
Missä Järjestelmä
Kuka Tite-ammattilainen
Milloin Rakennettaessa
Miksi Hyvä tapa
Print version |  PDF  | History: r8 < r7 < r6 < r5 | 
Topic revision: r8 - 29 Nov 2012 - 17:15:02 - TapioLinnimaki?
 

TUTWiki

Copyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TUTWiki? Send feedback