Фильтрация при обмене сообщениями между разными источниками

Фильтрация при обмене сообщениями между разными источниками.

То, как мы реализовали предыдущий пример, нельзя назвать передовой практикой, особенно с учетом необходимости обеспечения безопасности данных. Код в главном документе отправляет сообщение в определенный фрейм, но никак не контролирует то, каким документам позволено считывать это сообщение (данные сообщения смогут прочитать любые документы внутри iframe). Помимо этого код во фрейме iframe не проверяет источник и обрабатывает все полученные сообщения. Для того чтобы предотвратить злоупотребления такой реализацией, необходимо улучшить обе стороны коммуникационного процесса.

В следующем примере мы исправим ситуацию и продемонстрируем, как отвечать на сообщение из целевого документа, используя еще одно свойство события message — свойство source.

Листинг 13.17. Обмен сообщениями с конкретными источниками и целевыми документами

<!DOCTYPE html>

<html lang="ru">

<head>

<title>Обмен сообщениями между документами</title>

<link rel="stylesheet" href="messaging. css">

<script src="messaging. js"></script>

</head>

<body>

<section id="formbox"> form name="form">

<p>Ваше имя: <input type="text" name="name" id="name" required></p>

<p><input type="button" name="button" id="button" value="Отправить"></p>

</form>

</section>

<section id="databox">

<iframe id="iframe" src="http://www.domain2.com/iframe.html" width="500" height="350"></iframe>

</section>

</body>

</html>

Предполагается, что новый HTML-документ с кодом из листинга 13.17 расположен в домене www.domain1.com. Однако если вы внимательно просмотрите код, то обнаружите, что фрейм iframe загружает файл из другого местоположения в домене www.domain2.com. Для предотвращения злоупотреблений эти два местоположения необходимо объявить в коде JavaScript, точно указав, каким документам разрешено читать сообщения и откуда эти сообщения могут быть отправлены.

В коде из листинга 13.17 мы не только указываем HTML-файл, являющийся источником фрейма, как уже делали раньше, — теперь мы объявляем полный путь к другому местоположению (Www. domain2.com). Таким образом, главный документ находится в домене Www. domain1.com, а содержимое iframe — в домене www.domain2.com. В следующих примерах кода это условие принимается во внимание.

Function initiate(){

Var button=document. getElementById(‘button’); button. addEventListener(‘click’, send, false);

Window. addEventListener(‘message’, receiver, false);

}

Function send(){

Var name=document. getElementById(‘name’).value; var iframe=document. getElementById(‘iframe’);

Iframe. contentWindow. postMessage(name, ‘http://www.domain2.com’);

}

Function receiver(e){

If(e. origin==’http://www. domain2.com’){

Document. getElementById(‘name’).value=e. data;

}

}

Window. addEventListener(‘load’, initiate, false);

Обратите внимание на функцию send() в коде из листинга 13.18. В методе postMessage() теперь объявляется конкретный целевой домен для отправки сообщения (www.domain2.com). Прочитать это сообщение смогут только документы внутри iframe и принадлежащие указанному источнику.

В функции initiate() в листинге 13.18 мы также добавили прослуши-ватель события message. Задача этого прослушивателя, а также функции receiver() — получить ответ, отправленный документом из iframe. Подробнее об этом поговорим чуть позже.

Давайте пока что изучим код для фрейма и посмотрим, каким образом обрабатывается сообщение из конкретного источника, а также как отправить ответ на это сообщение (для описания структуры фрейма будем использовать старый HTML-документ из листинга 13.15).

Листинг 13.19. Отправка ответа главному документу (iframe. js)

Function initiate(){

Window. addEventListener(‘message’, receiver, false);

}

Function receiver(e){

Var databox=document. getElementById(‘databox’); if(e. origin==’http://www.domain1.com’){

Databox. innerHTML=’допустимое сообщение: ‘+e. data; e. source. postMessage(‘сообщение получено’, e. origin);

}else{

Databox. innerHTML=’недопустимый источник’;

}

}

Window. addEventListener(‘load’, initiate, false);

Фильтрация источника происходит очень просто: мы сравниваем значение свойства origin с доменом, который считаем допустимым источником сообщений. Если выясняется, что это правильный источник, то сообщение выводится на экран, а обратно с использованием значения свойства source отправляется ответ. Мы используем свойство origin, чтобы объявить, что данный ответ будет доступен только тому окну, которое отправило исходное сообщение. Теперь вернитесь к листингу 13.18 и посмотрите, как функция receiver() обрабатывает этот ответ.

Этот пример немного сложнее предыдущих. Мы работаем с двумя разными источниками, поэтому для тестирования примеров кода потребуются два разных домена (или субдомена). Замените названия доменов в коде фактическими именами ваших доменов и загрузите файлы для главного документа в один домен, а файлы для фрейма — в другой.

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

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *