Pull to refresh

JavaScript Cross Site (XSS) POST

Reading time 4 min
Views 13K
Недавно, в Dojo появилась возможность производить cross site POST запросы, т.е. отправка POST запросов на другие сайты, с другими доменными именами. Это событие осталось незамеченным в нашем сообществе JavaScript разработчиков. По крайней мере, никто и слова про это не сказал. А зря…

В один прекрасный момент понадобилась возможность осуществлять cross-site POST запросы. Естественно понимая, что на данный момент безопасность браузеров запрещает cross-site AJAX, был выбран вариант использования Flash-AJAX связки. Но все, же лично мне нравятся «чистые» JavaScript решения. Поэтому до конца мы все же не удовлетворились. Недавно утром пребывая в альфа состоянии сна, мне приснился принцип на основе которого, можно осуществлять XSS POST используя только JavaScript. Суть реализации XSS POST основана на особенностях хранения данных в свойстве window.name. Мысли пришли благодаря недавним сериям статей в Инете про window.name. Покопавшись в Google, сразу же нашлась уже готовая реализация. (Видать приснилось не только мне). Dojo как всегда впереди планеты всей www.sitepen.com/blog/2008/07/22/windowname-transport. Молодцы.


Как это работает


Принцип работы довольно подробно описан по ранее указанной ссылке. В двух словах: если изменить свойство window.name оно остается измененным пока браузер (вкладка-табулятор) открыт. Если изменить свойство на одном сайте, то его можно потом прочитать на другом. Т.е. при переходе от сайта к сайту браузер не очищает window.name. Причем данный механизм хранения значения window.name работает во всех браузерах. XSS POST транспорт, использует эту замечательную возможность. Другими словами: при отправке данных на другой сервер происходит следующее:
  1. загружаем страницу с иного сайта/домена
  2. эта страница оставляет свой след в window.name
  3. возвращаемся на свой сайт/домен
  4. считываем оставленный след из window.name

В добавок, для передачи POST запроса используется трюк c атрибутом target элемента form (принцип AJAX Uploader, Gmail Uploader файлов).
Ответ от сайта на который идет запрос должен быть в следующем формате:
<script>
window.name = ‘тут пишем то, что хотим передать’;
</script>

Соответственно данный подход не позволяет забрать данные без ведома владельца иного сайта, потому что ответ должен быть сформирован в определенном специфическом формате. Это обстоятельство сохраняет безопасность и защищает от XSS скрабинга. Т.е. по сути это чем-то похоже на механизм разрешения кросс-доменных запросов (cross-domain.xml) во Flash.


Более детально


  1. Создается iframe и вешается обработчик на событие onload.
  2. Если необходим просто GET запрос, то у iframe в атрибуте src устанавливается URL адрес ресурса. Если необходим POST запрос то динамически создается форма. Адрес ресурса уже указывается в атрибуте action объекта формы, а параметры передаются в элементах input (name=имя параметра, value=значение параметра). Чтобы ассоциировать iframe с формой (form) у нее ставится такой же идентификатор (атрибут id) что и у iframe. После генерации формы просто вызывается метод формы submit. Запрос произведен.
  3. Функция обратного вызова указанная в iframe срабатывает после того как данные загрузились. В нашем случаем загружается конструкция вида <script>window.name=’данные’</script> и данные попадают в свойство name объекта contentWindow. Задача обработчика достать эти данные. И если вы произведете обращение к iframe.contentWindow.name то будет отказано в доступе. Чтобы обойти эту проблему нужно вернуться в свой домен, делается это сменой значения аттриубута location объекта contentWindow. Например, можно указать адрес на пустой blank.html со своего домена или просто записать «about:blank» (iframe.contentWindow.location = ‘about:blank’). После этого можно считать данные из атрибута name.


Относительно текущей реализации от Dojo


Проанализировав их разработку
dojox.io.windowName.js мы нашли ряд значительных недостатков:
  1. Сильная зависимость от ядра, которое весит довольно «некисло».
  2. Необходимость наличия «resources/blank.html» файла.

В добавок:
  1. нам не понравился код, наше субъективное мнение – грязный код.
  2. для FireFox применяется дополнительные «телодвижения» (комментарий в исходниках относительно этого: FF2 allows unsafe sibling frame modification) – честно говоря мы так и не поняли для чего именно…

Нам захотелось улучшить текущее состояние XSS POST и, соответственно, написали свою реализацию, которая гораздо меньше по объему, самодостаточная и не привязана ни к одной из библиотек, код более чистый и оптимальный. Сравнивайте и судите сами:

Пример вызова:
SRAX.XSS.post('http://okarta.ru/scripts/post-xhr.php', 'a=a1&b=b2', function(text){
  alert(text)
})




XSS POST в нашей реализации в дальнейшем будет дорабатываться и развиваться, соответственно обрастет большим количеством методов и параметров. Кому интересно, сможет всегда скачать более новую версию.
Как всегда существует общий недостаток: при использовании iframe для передачи данных в браузере появляется история, т.е. активируется кнопка «Назад». Может кто знает как вставить iframe без срабатывания истории? Было замечательно устранить этот недостаток.


Зачем это надо


Давно существуют механизмы XSS GET запроса данных. И по сей день зачастую их бывает достаточно для решения большего количества задач. Но все же, иногда бывают моменты, когда ограничения GET запросов не позволяют качественно решить нужную задачу. К примеру, Google AJAX Language API реализовано на XSS GET запросах и имеет ограничение на количество переводимых символов за один запрос – 500 символов. Теперь имея XSS POST данное ограничение можно смело убрать. Есть и другие случаи, когда XSS POST жизненно необходим. Грамотным специалистам XSS POST транспорт даже очень пригодится.

Автор статьи – Руслан Синицкий, соавтор – Александров К. М. (m007)
Tags:
Hubs:
+52
Comments 73
Comments Comments 73

Articles