Обратный вызов JSONP не выполняется при запуске на локальном хосте - PullRequest
11 голосов
/ 02 августа 2009

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

По сути, я старался изо всех сил пытаться протестировать JSONP, чтобы я мог реализовать веб-сервис JSON, который могут использовать другие сайты. Я занимаюсь разработкой на локальном хосте - в частности, на Visual Studio 2008 и на встроенном веб-сервере Visual Studio 2008.

Так что в качестве теста JSONP с jQuery я реализовал следующее:

$().ready(function() {
  debugger;
  try {
    $.getJSON("<%= new Uri(Request.Url, "/").ToString() %>XssTest?callback=?", function(data) {
        alert(data.abc);
    });
  } catch (err) {
    alert(err);
  }
});

и на сервере ..

<%= Request["callback"] %>({abc : 'def'})

Так что в итоге я устанавливаю точку останова на сервере и получаю точку останова на первом «отладчике»; statment в скрипте на стороне клиента и на сервере. URL JSONP действительно вызывается после загрузки страницы. Это прекрасно работает.

Проблема, с которой я столкнулся, заключалась в том, что обратный вызов никогда не будет выполнен. Я проверял это как в IE8, так и в Firefox 3.5. Ни один из них не вызвал бы обратный вызов. Улов (err) также никогда не был достигнут. Ничего не случилось вообще!

Я застрял на этой неделе и даже протестировал HTTP-запрос с ручным ключом в Telnet на указанном порту, чтобы убедиться, что сервер возвращает формат ...

callbackfn({abc : 'def'})

.. и это так.

Тогда меня осенило, что если я изменю имя хоста с локального на локальный с помощью глобализатора ('.'), То есть http://localhost.:41559/ вместо http://localhost:41559/ (да, добавив точку к любое имя хоста допустимо, именно для DNS то же, что global:: для пространств имен C #). И тогда это сработало! Internet Explorer и Firefox 3.5 наконец-то показали мне предупреждающее сообщение, когда я только что добавил точку.

Так что это заставляет меня задуматься, что здесь происходит? Почему поздняя генерация тегов скрипта будет работать с именем хоста в Интернете, а не с простым localhost? Или это правильный вопрос?

Очевидно, это реализовано в целях безопасности, но что они пытаются обезопасить? И, заставив его работать с точкой, я только что открыл дыру в безопасности в этой функции безопасности?

Кстати, мой файл hosts, хотя и измененный для других хостов, не имеет ничего особенного с localhost; 127.0.0.1 / :: 1 по умолчанию все еще на месте без переопределений ниже.

ПОСЛЕДУЮЩИЙ: Я преодолел это для целей местного развития, добавив:

127.0.0.1   local.mysite.com

.. в мой файл hosts, затем добавьте следующий код в мой global.asax:

protected void Application_BeginRequest(object sender, EventArgs e)
{
    if (Request.Headers["Host"].Split(':')[0] == "localhost")
    {
        Response.Redirect(
            Request.Url.Scheme
            + "://"
            + "local.mysite.com"
            + ":" + Request.Url.Port.ToString()
            + Request.Url.PathAndQuery
            , true);
    }
}

Ответы [ 2 ]

3 голосов
/ 02 августа 2009

Я собираюсь выбросить ответ там; после некоторой мысли я пришел к своим собственным выводам.

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

Веб-сайт может просто просмотреть список портов и продолжать вызывать localhost для разных портов и путей. «Локальный хост» - это одно из немногих имен хостов DNS, которые имеют динамическое значение в зависимости от того, когда и где он запрашивается, делая потенциальные цели уязвимыми. И да, тот факт, что добавление точки (.) К 'localhost' ('localhost.') Приводит к работающему обходному пути, обнажает уязвимость безопасности, но предлагает [предварительный] обходной путь для целей разработки.

Лучшим подходом является сопоставление петлевого IP-адреса с новой записью имени хоста в файле hosts, чтобы он работал локально, не был подвержен «исправлению» обновлением браузера и не работал нигде, кроме как на рабочая станция разработки.

1 голос
/ 12 августа 2009

У меня похожая проблема. Большинство решений, которые я пробовал, работают с IE (7), но мне трудно заставить Firefox (3.5.2) играть в мяч.

Я установил HttpFox, чтобы увидеть, как ответы моего сервера интерпретируются на клиенте, и я получаю NS_ERROR_DOM_BAD_URI. Моя ситуация немного отличается от вашей, хотя я пытаюсь вызвать обратный вызов JSONP на тот же сайт, с которого пришла страница хостинга, а затем этот вызов отвечает перенаправлением 302 на другой сайт. (Я использую перенаправление как удобный способ получения файлов cookie с обоих доменов, возвращаемых в браузер.)

Я использую jQuery, и я изначально пытался сделать стандартный вызов AJAX через $ .ajax (). Я подумал, что поскольку первоначальный запрос был на тот же сайт, что и на странице хостинга, Firefox просто следовал за ответом 302 на другой домен. Но нет, похоже, это было нарушением защиты XSS. (Обратите внимание, что вопреки тому, что Возвращает перенаправление в ответ на запрос XHR , jQuery следует перенаправлению 302 для стандартного вызова dataType = "json": перенаправление в тот же домен работает нормально; перенаправление в другой домен генерирует NS_ERROR_DOM_BAD_URI в браузере.) Кроме того, я не вижу, почему нельзя перенаправить тот же домен 302 на другие домены - в конце концов, перенаправление перенаправляется на домен страницы хостинга, так почему не доверять? Если вас беспокоят атаки с использованием сценариев, тогда маршрут JSONP в любом случае открыт для злоупотреблений ...

jQuery's $ .getJSON () с? Callback =? суффикс также терпит неудачу в Firefox с той же ошибкой. Как и использование $ .getScript () для прокрутки моего собственного тега JSONP .

То, что кажется работающим, это наличие ранее существующего в HTML, а затем использование $ ("jsonp"). Attr ("src ", url +"? callback = myCallback ") для вызова вызова JSONP. Если я это сделаю, то будет выполнено междоменное перенаправление 302, и я передам свой ответ JSON в myCallback (который я определил одновременно с тегом ).

И, да, я разрабатываю все это, используя Cassini с localhost: порт URL-адреса. Кассини не будет отвечать на URL, не относящиеся к локальному хосту, поэтому я не могу с легкостью попробовать local.mysite.com, чтобы посмотреть, как это повлияет на решения, которые я пробовал выше. Однако вставка точки в конце localhost, похоже, исправила все мои проблемы!

Теперь я могу вернуться к стандартному вызову $ .ajax ({... dataType: "jsonp" ...}) с localhost __.__: port вместо localhost: port и все хорошо. Мне интересно, что изменение атрибута src тега script, который уже существует в HTML страницы, позволяет вызывать обычные URL-адреса локального хоста - я полагаю, что, следуя вашему мыслительному процессу, это может быть еще одной уязвимостью безопасности.

...