JSONP tai "JSON, jossa on täyte" on lisäys JSON -perusmuotoon . Se tarjoaa tavan pyytää tietoja eri verkkotunnuksessa sijaitsevalta palvelimelta, mikä on kielletty tyypillisissä verkkoselaimissa toimialueen rajoituskäytännön vuoksi .
Heinäkuussa 2005 George Jempty ehdotti mahdollisuutta lisätä JSON:n eteen valinnainen muuttujamäärittely. [1] [2] Alkuperäisen JSONP-ehdotuksen, jossa täyte on takaisinsoittotoiminto, teki todennäköisesti Bob Ippolito joulukuussa 2005 [3] ja sitä käyttävät nykyään monet Web 2.0 -sovellukset, kuten Dojo Toolkit , Google Web Toolkit , [4] ja verkkopalvelut .
Toimialueen rajoituskäytännön mukaan palvelimella oleva verkkosivuexample1.com ei voi ottaa yhteyttä muuhun palvelimeen kuin example2.com. JSONP-tekniikka perustuu siihen, että selaimen suojauskäytäntö ei estä HTML-elementin <script type="text/javascript" src="…"/> käyttöä päästäkseen muihin palvelimiin kuin palvelimeen, jolta sivu on ladattu. Käyttämällä Open Policy on Elements -käytäntöä <script>jotkin sivut käyttävät niitä JavaScript-koodin lataamiseen, joka toimii muista lähteistä dynaamisesti luoduilla JSON-tiedoilla. JSONP-pyynnöt eivät vastaanota JSON-koodia, vaan mielivaltaista JavaScript-koodia. Niitä käsittelee JavaScript-tulkki, ei JSON-jäsennys. JSONP:n käyttöön liittyy vakavia turvallisuusriskejä, useimmissa tilanteissa CORS : n käyttö on paras valinta.
Mallin kaavio voidaan kuvata käyttämällä pyyntöä tietylle URL -osoitteelle , joka palauttaa JSON-tiedot. JavaScript-ohjelma voi pyytää tätä URL-osoitetta esimerkiksi XMLHttpRequestin kautta . Oletetaan, että Foo-objektin UserId on 1234. Selain , joka pyytää URL -osoitetta http://server2.example.com/Users/1234, joka välittää tunnuksen 1234, saa vastauksen seuraavassa muodossa:
{ "Nimi" : "Foo" , "Id" : 1234 , "Sijoitus" : 7 }Kolmannen osapuolen vastauksessa olevat JSON-tiedot luodaan yleensä dynaamisesti URL-osoitteessa välitettyjen pyyntöparametrien perusteella.
Seuraava HTML-elementti <script>määrittää attribuutiksi srclinkin, joka palauttaa JSON:n:
< script type = "application/javascript" src = "http://server2.example.com/Users/1234" > </ script >Selain puolestaan lataa tiedoston script, jäsentää sen sisällön, tulkitsee raaka JSON-tiedot lohkoksi ja antaa syntaksivirheen. Vaikka tiedot on tulkittu JavaScript-olieraaliksi, niitä ei voida käyttää selaimessa ajettavalla JavaScriptillä, koska objektiliteraaleja ei ole saatavilla ilman muuttujaan liittämistä.
JSONP-mallissa tunnisteen <script>src-attribuutin osoittama URL-osoite palauttaa JSON-tiedot funktiokutsuun käärittynä. Siinä tapauksessa JavaScript-ympäristössä jo määritetty funktio voi käsitellä JSON-tietoja. JSONP-täyte voi näyttää tältä:
functionCall ({ "Nimi" : "Foo" , "Id" : 1234 , "Rank" : 7 });Funktion kutsu on "P" JSONP-sanassa - "täyte" (täyte, " sisennys ") puhtaan JSONin ympärillä tai joidenkin lähteiden mukaan [5] - "etuliite". Sopimuksen mukaan selain välittää takaisinsoittotoiminnon nimen nimettynä pyyntöparametrina, tavallisesti käyttäen nimeä jsonptai callbackpyynnössä palvelimelle, ts.
< script type = "text/javascript" src = "http://server2.example.com/Users/1234?jsonp=parseResponse" > </ script >Tässä esimerkissä täyttö tulee olemaan seuraava:
parseResponse ({ "Nimi" : "Foo" , "Id" : 1234 , "Rank" : 7 });Täyte (etuliite) on yleensä selaimen suorituskontekstin sisällä määritetyn takaisinsoittotoiminnon nimi. Toiminnon nimen lisäksi etuliite voi tarkoittaa muuttujan nimeä, operaattoria iftai mitä tahansa muuta JavaScript-operaattoria. Vastaus JSONP-pyyntöön (tarkasti ottaen JSONP-mallin mukainen pyyntö) ei ole JSON-objekti, eikä selain käsittele sitä sellaisena. "Täyte" voi olla mikä tahansa JavaScript-lauseke, eikä se edellytä, että JSON on sisällä. Mutta se on yleensä JavaScript-kappale, joka käyttää funktiokutsua joihinkin JSON-tietoihin.
Toisin sanoen tyypillinen JSONP:n käyttö tarjoaa verkkotunnusten välisen pääsyn olemassa olevaan JSON- sovellusliittymään käärimällä JSON-täytön funktiokutsuun.
JSONP on järkevä vain, kun sitä käytetään komentosarjaelementin kanssa. Jokaiselle uudelle JSONP-pyynnölle selaimen on lisättävä uusi elementti <script>tai käytettävä olemassa olevaa elementtiä. Ensimmäinen käsittely, uuden skriptielementin lisääminen, tehdään dynaamisella DOM-käsittelyllä, ja sitä kutsutaan komentosarjaelementin injektioksi . Elementti <script>lisätään HTML DOM:iin siten, että halutun JSONP-päätepisteen URL-osoite on "src"-attribuutissa.
Tämän dynaamisen komentosarjaelementin lisäyksen tekee yleensä javascript-apukirjasto. jQueryllä ja muilla kehyksillä on aputoimintoja JSONP:lle; on myös erillisiä ratkaisuja [6] [7] .
Dynaamisesti lisätty komentosarjaelementti JSONP-kutsuille näyttää tältä:
< script type = "text/javascript" src = "http://server2.example.com/Users/1234?jsonp=parseResponse" > </ script >Kun elementti on lisätty, selain käsittelee sen ja suorittaa HTTP GET:n src-URL-osoitteelle saadakseen sisällön. Sitten selain käsittelee palautettua hyötykuormaa JavaScriptina. Yleensä tämä on toiminnon suorittamista.
Tässä mielessä JSONP:n käyttöä voidaan kuvata sallivan selainsivujen ohittaa toimialueen rajoituskäytännön lisäämällä komentosarjaelementin.
Muilta palvelimilta peräisin olevien komentosarjatunnisteiden lisääminen mahdollistaa etäpalvelimien sekoittamisen verkkosivustolle mitä tahansa sisältöä . Jos etäpalvelimissa on haavoittuvuuksia, jotka sallivat JavaScriptin sekoittamisen, alkuperäisen palvelimen tarjoama sivu on suuremmassa vaarassa.
Parhaillaan ryhdytään määrittelemään turvallisempi, tiukempi JSON-P:n [8] alijoukko , jonka selaimet voivat pakottaa sisällyttämään pyytäessään komentosarjaa tietyllä MIME-tyypillä, kuten "application/json-p". Jos vastausta ei jäsennetä tiukkana JSON-P:nä, selain saattaa antaa virheilmoituksen tai yksinkertaisesti jättää huomioimatta koko vastauksen. Kuitenkin tällä hetkellä ainoa kelvollinen MIME-tyyppi JSONP:lle on "application/javascript" [9] .
Primitiiviset JSONP-isännät ovat alttiita sivustojen väliselle pyyntöväärennökselle (CSRF tai XSRF) [10] . Koska HTML-tunnisteeseen <script>ei sovelleta verkkotunnuksen rajoituskäytäntöä todellisissa selaintoteutuksissa, haitallinen sivu voi pyytää ja vastaanottaa toiselle sivustolle kuuluvaa JSON-dataa. Tämä mahdollistaa JSON-tietojen käsittelyn haitallisen sivun yhteydessä, mikä saattaa paljastaa salasanoja tai muita arkaluonteisia tietoja, jos käyttäjä on kirjautunut toiselle sivustolle.
Tämä aiheuttaa ongelmia vain, jos JSON-koodatut tiedot sisältävät arkaluontoisia tietoja, joita ei saa paljastaa kolmannelle osapuolelle, ja palvelin luottaa selaimen toimialueen rajoituskäytäntöön estääkseen tiedonsiirron huonon pyynnön sattuessa. Ongelmaa ei ole, jos palvelin itse määrittää pyynnön asianmukaisuuden ja välittää tietoja vain, jos pyyntö on kelvollinen. Evästeet eivät itsessään ole riittävä tapa määrittää pyynnön laillisuus. Pelkästään evästeiden käyttö on altis sivustojen väliselle pyyntöväärennökselle .
JSONPP ( eng. parameterized JSON with padding - "parameterized JSON with padding") - JSONP-idean kehittäminen.
JSONPP sisältää lähde-URL-osoitteen, JSON-tietoja käsittelevän toiminnon nimen, eval-merkkijonon tietojen vastaanottamisen jälkeen ja eval-merkkijonon, kun tiedot on valmis:
JSON_call ( SRC , JSONP , JSONPP , ONLOAD );lopulta kääntyy
ans = JSONP ( SRC ) { eval ( JSONPP ( ans )); eval ( LATAA ); }Yleensä parametrien määrällä ei ole merkitystä itse JSONPP-idealle. SRC, JSONP, JSONPP (ja niiden käsittely palvelinpuolella ja sitten asiakaspuolella) riittää, jotta se on JSONPP. Harkitse esimerkkiä työskentelystä S3DB-palvelun kanssa.
function s3db_jsonpp_call ( src , next_eval ){ var call = "call_" + Math . satunnainen (). toString (). korvaa ( /\./g , "" ); var headID = asiakirja . getElementsByTagName ( "head" )[ 0 ]; var script = asiakirja . createElement ( 'script' ); käsikirjoitus . id = soita ; käsikirjoitus . type = 'text/javascript' ; // käyttäen täytettyä, parametroitua json-komentoa src = src + "&format=json&jsonp=s3db_jsonpp&jsonpp=" + next_eval + "&onload=remove_element_by_id('" + komentosarja . id + "')" ; käsikirjoitus . src = src ; headID . appendChild ( script ); // nouta vastaus } function s3db_jsonpp ( ans , jsonpp ){ eval ( jsonpp ); paluu ans ; } function remove_element_by_id ( id ){ var e = asiakirja . getElementById ( id ); e . parentNode . poistaLapsi ( e ); return false ; }Esimerkissä funktio s3db_jsonpp_call()luo komentosarjaelementin DOM:n head-osaan, jonka src vastaa JSONPP-kutsua.
Kun vastaus on saatu palvelimelta, sitä kutsutaan s3db_jsonpp() - se välitetään puheluparametreissa, kuten sen pitäisi olla JSONP-sääntöjen mukaan.
Sisäisesti s3db_jsonpp()toimii eval(jsonpp)ja ans:n arvo palautetaan.
Kutsu eval(onload)johtaa suoritukseen remove_element_by_id()luodun skriptin id:llä head-päässä ja sen seurauksena sen poistamiseen, koska sitä ei enää käytetä joka tapauksessa, koska esimerkin id luotiin satunnaisesti aivan funktion alussa s3db_jsonpp_call(). Tämä puhelu on palvelimen vastauksessa.