Обратный вызов 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 - я думаю, что после вашего мыслительного процесса это может быть другой уязвимостью безопасности.