JSONP

Материал из Википедии — свободной энциклопедии
Перейти к: навигация, поиск

JSONP или «JSON with padding» (JSON с набивкой) это дополнение к базовому формату JSON. Он предоставляет способ запросить данные с сервера, находящегося в другом домене — операцию, запрещённую в типичных веб-браузерах из-за политики ограничения домена.

По правилу ограничения домена веб-страница, доставляемая с сервера server1.example.com, не может нормально связаться с сервером, отличным от server1.example.com. Исключением является HTML-элемент <script>. Эксплуатируя открытую политику для элементов <script>, некоторые страницы используют их, чтобы загружать JavaScript-код, оперирующий динамически создаваемыми JSON-данными из других источников. Этот шаблон поведения известен как JSONP. Запросы для JSONP получают не JSON, а произвольный JavaScript-код. Они обрабатываются интерпретатором JavaScript, а не парсером JSON.

О JSONP возникают критические отзывы. Cross-origin resource sharing (CORS) является более новым методом получения данных с сервера в другом домене. Он учитывает критику.

Как это работает[править | править вики-текст]

Чтобы понять, как работает этот паттерн, сперва представьте запрос по некоему URL, возвращающий JSON-данные. Программа на JavaScript могла бы запросить этот URL, к примеру, посредством XMLHttpRequest. Предположим, UserId объекта Foo равен 1234. Браузер, запрашивающий URL http://server2.example.com/Users/1234, передав Id равный 1234, получил бы ответ вроде:

   {"Name": "Foo", "Id": 1234, "Rank": 7}

Эти JSON-данные могли бы быть динамически созданными согласно параметрам запроса, переданным в URL.

Ниже HTML-элемент <script> указывает в качестве атрибута src ссылку, возвращающую JSON:

 <script type="text/javascript"
         src="http://server2.example.com/Users/1234">
 </script>

В свою очередь, браузер скачает файл script, разберёт его содержимое, интерпретирует сырые JSON-данные как блок и выкинет ошибку синтаксиса. Даже если данные были интерпретированы как литеральный объект JavaScript, к нему невозможно получить доступ из JavaScript, выполняемого в браузере, поскольку без присвоения переменной объектные литералы недоступны.

В паттерне JSONP URL, на который указывает атрибут src тэга <script>, возвращает данные JSON, обёрнутые в вызов функции. В подобном случае функция, уже определённая в среде JavaScript, может манипулировать JSON-данными. Начинка JSONP может выглядеть так:

   functionCall({"Name": "Foo", "Id": 1234, "Rank": 7});

Вызов функции это и есть «P» в слове JSONP — «padding» (набивка, «отступ») вокруг чистого JSON, или, согласно некоторым источникам[1] — «префикс». По соглашению, браузер передаёт имя функции обратного вызова как именованный параметр запроса, обычно используя имя jsonp или callback в запросе к серверу, то есть,

 <script type="text/javascript"
         src="http://server2.example.com/Users/1234?jsonp=parseResponse">
 </script>

В данном примере начинка будет такова:

   parseResponse({"Name": "Foo", "Id": 1234, "Rank": 7});

Набивка[править | править вики-текст]

В то время как набивка (префикс) является обычно именем функции обратного вызова, определённой внутри контекста выполнения в браузере, она может также быть переменной, оператором if, или любым другим оператором JavaScript. Ответ на JSONP-запрос (строго говоря — запрос, соответствующий паттерну JSONP) не является JSON и не парсится как JSON; начинка может быть любым выражением на JavaScript, и вовсе не требует, чтобы внутри обязательно был JSON. Но обычно это фрагмент JavaScript, применяющий вызов функции к неким JSON-данным.

Другими словами, типичное применение JSONP предоставляет междоменный доступ к существующему JSON API путём оборачивания начинки JSON в вызов функции.

Инъекция элемента script[править | править вики-текст]

JSONP имеет смысл только когда используется с элементом script. Для каждого нового JSONP-запроса браузер должен добавить новый элемент <script> или использовать существующий. Первая манипуляция — добавление нового элемента script — осуществляется через динамическое манипулирование DOM, и известна как инъекция элемента script. Элемент <script> впрыскивается в HTML DOM, с URL желаемой конечной точки JSONP в атрибуте «src».

Эта динамическая инъекция элемента script обычно выполняется вспомогательной библиотекой javascript. У jQuery и других фреймворков имеются вспомогательные функции для JSONP; существуют также и отдельные решения.[2][3]

Динамически вставляемый элемент script для вызовов JSONP выглядит следующим образом:

 <script type="text/javascript"
         src="http://server2.example.com/Users/1234?jsonp=parseResponse">
 </script>

После вставки элемента, браузер обрабатывает его и выполняет HTTP GET для src URL, получая содержимое. Затем браузер обрабатывает возвращённую полезную начинку как javascript. Обычно это выполнение функции.

В этом смысле применение JSONP можно охарактеризовать как разрешить браузерным страницам обойти политику ограничения домена путём вставки элемента script.

Соображения безопасности[править | править вики-текст]

Включение тэгов script с других серверов позволяет удалённым серверам подмешать в веб-сайт любое содержимое. Если у удалённых серверов есть уязвимости, допускающие подмешивание JavaScript, страница, предоставляемая оригинальным сервером, подвергается повышенному риску.

В настоящее время предпринимаются шаги, чтобы определить более безопасное строгое подмножество JSON-P[4], которое браузеры могли бы принудительно включать при запросах скрипта со специфичным MIME-типом, как например «application/json-p». Если ответ не парсится как строгий JSON-P, браузер мог бы выводить ошибку или просто игнорировать весь ответ. Однако, на текущий момент единственным правильным MIME-типом для JSONP является «application/javascript».[5]

Подделка межсайтовых запросов[править | править вики-текст]

Примитивные размещения JSONP подвержены опасности подделки межсайтовых запросов (CSRF или XSRF).[6] Поскольку HTML-тэг <script> не подчиняется политике ограничения домена в реальных реализациях браузеров, вредоносная страница может запросить и получить JSON-данные, принадлежащие другому сайту. Это позволит данным в формате JSON быть обработанными в контексте вредоносной страницы, возможно, раскрывая пароли или другие секретные данные, если пользователь залогинен на другом сайте.

Это вызывает проблемы только если данные, закодированные в JSON, содержат конфиденциальную информацию, которую нельзя разглашать третьей стороне, и сервер полагается на политику ограничения домена браузера для блокировки передачи данных в случае неправильного запроса. Проблема не существует, если сервер самостоятельно определяет уместность запроса, передавая данные только если запрос правильный. Cookies сами по себе не являются адекватным способом определения правомерности запроса. Использование одних лишь только cookies подвержено подделке межсайтовых запросов.

История[править | править вики-текст]

В июле 2005 года Джордж Джемпти (George Jempty) предложил возможность предварять JSON необязательным объявлением переменной.[7][8] Исходное предложение JSONP, где набивкой является функция обратного вызова, скорее всего было сделано Бобом Ипполито (Bob Ippolito) в декабре 2005 года[9] и используется ныне многими Web 2.0-приложениями, такими как Dojo Toolkit, Google Web Toolkit,[10] и веб-службами.

Примечания[править | править вики-текст]

  1. Experimental RDF result set to JSON translator. Проверено 20 февраля 2012. Архивировано из первоисточника 17 января 2013.
  2. example jsonp library on pastebin. Архивировано из первоисточника 17 января 2013.
  3. jQuery's $.getJSON utility. Архивировано из первоисточника 17 января 2013.
  4. Safer cross-domain Ajax with JSON-P/JSONP. JSON-P.org. Проверено 30 октября 2011. Архивировано из первоисточника 17 января 2013.
  5. Grey, Eli Is this safe for providing JSONP?. stackoverflow.com (27 июня 2010). Проверено 7 сентября 2012. Архивировано из первоисточника 13 февраля 2013.
  6. Grossman, Jeremiah Advanced Web Attack Techniques using GMail (January 27, 2006). Проверено 3 июля 2009. Архивировано из первоисточника 17 января 2013.
  7. eval'ing JSON (July 19, 2005).
  8. json: Message: Re: Comments (August 17, 2005). Архивировано из первоисточника 17 января 2013.
  9. Remote JSON - JSONP. from __future__ import *. Bob.pythonmac.org (December 5, 2005). Проверено 8 сентября 2008. Архивировано из первоисточника 17 января 2013.
  10. GWT Tutorial: How to Read Web Services Client-Side with JSONP. Google Web Toolkit Applications (February 6, 2008). Проверено 3 июля 2009. Архивировано из первоисточника 17 января 2013.

Ссылки[править | править вики-текст]