Обратный вызов JSONP не выполняется при запуске на локальном хосте

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

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

Итак, как тестовый запуск JSONP w/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 на стороне клиента script, а также на сервере. URL-адрес JSONP действительно вызывается после загрузки страницы. Это отлично работает.

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

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

callbackfn({abc : 'def'})

.. и это.

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

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

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

Кстати, файл моих хостов, измененный для других хостов, не имеет ничего общего с 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);
    }
}

Ответ 1

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

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

Веб-сайт может просто просматривать список портов и поддерживать вызов localhost на разных портах и ​​путях. "Локальный хост" - одно из немногих имен хостов DNS, которые имеют динамический смысл, в зависимости от того, когда и где он запрашивается, делая уязвимые потенциальные объекты уязвимыми. И да, тот факт, что добавление точки (.) В "localhost" ( "localhost." ) Создает рабочий обход, обнаруживает уязвимость безопасности, но предлагает [предварительный] обходной путь для развития пупок.

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

Ответ 2

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

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

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

jQuery $.getJSON() с? callback =? суффикс также терпит неудачу в Firefox с той же ошибкой. Как и использование $.getScript(), чтобы свернуть мой собственный JSONP <script> тег.

Что, кажется, работает, имеет уже существовавший < script id = "jsonp" type = "text/javascript" > </script> в HTML, а затем с помощью $( "jsonp" ). attr ( "src", url + "? callback = myCallback" ) для вызова вызова JSONP. Если я это сделаю, тогда будет выполняться переадресация перекрестного домена 302, и я получаю ответ JSON, переданный в myCallback (который я определил одновременно с тегом script/ > ).

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

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