Что нужно проверять чтобы postmessage был безопасным

от admin

Window.postMessage()

The window.postMessage() method safely enables cross-origin communication between Window objects; e.g., between a page and a pop-up that it spawned, or between a page and an iframe embedded within it.

Normally, scripts on different pages are allowed to access each other if and only if the pages they originate from share the same protocol, port number, and host (also known as the «same-origin policy»). window.postMessage() provides a controlled mechanism to securely circumvent this restriction (if used properly).

Broadly, one window may obtain a reference to another (e.g., via targetWindow = window.opener ), and then dispatch a MessageEvent on it with targetWindow.postMessage() . The receiving window is then free to handle this event as needed. The arguments passed to window.postMessage() (i.e., the «message») are exposed to the receiving window through the event object.

Syntax

Parameters

Data to be sent to the other window. The data is serialized using the structured clone algorithm. This means you can pass a broad variety of data objects safely to the destination window without having to serialize them yourself.

Specifies what the origin of this window must be for the event to be dispatched, either as the literal string «*» (indicating no preference) or as a URI. If at the time the event is scheduled to be dispatched the scheme, hostname, or port of this window’s document does not match that provided in targetOrigin , the event will not be dispatched; only if all three match will the event be dispatched. This mechanism provides control over where messages are sent; for example, if postMessage() was used to transmit a password, it would be absolutely critical that this argument be a URI whose origin is the same as the intended receiver of the message containing the password, to prevent interception of the password by a malicious third party. Always provide a specific targetOrigin , not * , if you know where the other window’s document should be located. Failing to provide a specific target discloses the data you send to any interested malicious site.

A sequence of transferable objects that are transferred with the message. The ownership of these objects is given to the destination side and they are no longer usable on the sending side.

Return value

The dispatched event

A window can listen for dispatched messages by executing the following JavaScript:

The properties of the dispatched message are:

The object passed from the other window.

The origin of the window that sent the message at the time postMessage was called. This string is the concatenation of the protocol and «://», the host name if one exists, and «:» followed by a port number if a port is present and differs from the default port for the given protocol. Examples of typical origins are https://example.org (implying port 443 ), http://example.net (implying port 80 ), and http://example.com:8080 . Note that this origin is not guaranteed to be the current or future origin of that window, which might have been navigated to a different location since postMessage was called.

A reference to the window object that sent the message; you can use this to establish two-way communication between two windows with different origins.

Security concerns

If you do not expect to receive messages from other sites, do not add any event listeners for message events. This is a completely foolproof way to avoid security problems.

If you do expect to receive messages from other sites, always verify the sender’s identity using the origin and possibly source properties. Any window (including, for example, http://evil.example.com ) can send a message to any other window, and you have no guarantees that an unknown sender will not send malicious messages. Having verified identity, however, you still should always verify the syntax of the received message. Otherwise, a security hole in the site you trusted to send only trusted messages could then open a cross-site scripting hole in your site.

Always specify an exact target origin, not * , when you use postMessage to send data to other windows. A malicious site can change the location of the window without your knowledge, and therefore it can intercept the data sent using postMessage .

Secure shared memory messaging

If postMessage() throws when used with SharedArrayBuffer objects, you might need to make sure you cross-site isolated your site properly. Shared memory is gated behind two HTTP headers:

  • Cross-Origin-Opener-Policy with same-origin as value (protects your origin from attackers)
  • Cross-Origin-Embedder-Policy with require-corp or credentialless as value (protects victims from your origin)

To check if cross origin isolation has been successful, you can test against the crossOriginIsolated property available to window and worker contexts:

Examples

Notes

Any window may access this method on any other window, at any time, regardless of the location of the document in the window, to send it a message. Consequently, any event listener used to receive messages must first check the identity of the sender of the message, using the origin and possibly source properties. This cannot be overstated: Failure to check the origin and possibly source properties enables cross-site scripting attacks.

As with any asynchronously-dispatched script (timeouts, user-generated events), it is not possible for the caller of postMessage to detect when an event handler listening for events sent by postMessage throws an exception.

After postMessage() is called, the MessageEvent will be dispatched only after all pending execution contexts have finished. For example, if postMessage() is invoked in an event handler, that event handler will run to completion, as will any remaining handlers for that same event, before the MessageEvent is dispatched.

The value of the origin property of the dispatched event is not affected by the current value of document.domain in the calling window.

For IDN host names only, the value of the origin property is not consistently Unicode or punycode; for greatest compatibility check for both the IDN and punycode values when using this property if you expect messages from IDN sites. This value will eventually be consistently IDN, but for now you should handle both IDN and punycode forms.

The value of the origin property when the sending window contains a javascript: or data: URL is the origin of the script that loaded the URL.

Using window.postMessage in extensions Non-standard

window.postMessage is available to JavaScript running in chrome code (e.g., in extensions and privileged code), but the source property of the dispatched event is always null as a security restriction. (The other properties have their expected values.)

It is not possible for content or web context scripts to specify a targetOrigin to communicate directly with an extension (either the background script or a content script). Web or content scripts can use window.postMessage with a targetOrigin of «*» to broadcast to every listener, but this is discouraged, since an extension cannot be certain the origin of such messages, and other listeners (including those you do not control) can listen in.

Content scripts should use runtime.sendMessage to communicate with the background script. Web context scripts can use custom events to communicate with content scripts (with randomly generated event names, if needed, to prevent snooping from the guest page).

Lastly, posting a message to a page at a file: URL currently requires that the targetOrigin argument be «*» . file:// cannot be used as a security restriction; this restriction may be modified in the future.

JavaScript
.postMessage () и MessageEvent

report this ad

параметры
сообщение
targetOrigin
перечислить optional

Начиная

Что такое .postMessage () , когда и почему мы его используем

.postMessage() — способ безопасно разрешить связь между скриптами с поперечным началом.

Обычно две разные страницы могут напрямую взаимодействовать друг с другом с использованием JavaScript, когда они находятся под одним и тем же источником, даже если один из них встроен в другой (например, iframes ) или один из них открывается из другого (например, window.open() ). С .postMessage() вы можете обойти это ограничение, оставаясь в безопасности.

Вы можете использовать .postMessage() когда у вас есть доступ к JavaScript-коду обоих страниц. Поскольку получателю необходимо проверить отправителя и обработать сообщение соответствующим образом, вы можете использовать этот метод только для связи между двумя имеющимися у вас сценариями.

Мы построим пример для отправки сообщений дочернему окну и отображения сообщений в дочернем окне. Предполагается, что страница родителя / отправителя будет http://sender.com а страница ребенка / получателя будет считаться http://receiver.com для примера.

Отправка сообщений

Чтобы отправлять сообщения в другое окно, вам нужно иметь ссылку на его window объект. window.open() возвращает ссылочный объект только что открытого окна. Для других методов , чтобы получить ссылку на объект окна, увидеть объяснение под otherWindow параметром здесь .

Добавьте textarea и send button которые будут использоваться для отправки сообщений дочернему окну.

Отправьте текст textarea с помощью .postMessage(message, targetOrigin) когда button .

Чтобы отправлять и получать объекты JSON вместо простой строки, могут использоваться методы JSON.stringify() и JSON.parse() . Transfarable Object может быть предоставлен в качестве третьего необязательного параметра метода .postMessage(message, targetOrigin, transfer) , но поддержка браузера по-прежнему отсутствует даже в современных браузерах.

В этом примере, поскольку наш приемник считается http://receiver.com page, мы вводим его url как targetOrigin . Значение этого параметра должно соответствовать origin от childWindow объекта для сообщения , которое требуется отправить. Можно использовать * в качестве wildcard но настоятельно рекомендуется избегать использования подстановочного знака и всегда устанавливать этот параметр для конкретного источника получателя по соображениям безопасности .

Получение, проверка и обработка сообщений

Код в этой части должен быть помещен на страницу получателя, которая для нашего примера — http://receiver.com .

Чтобы получать сообщения, необходимо прослушать message event в window .

Когда сообщение получено, необходимо выполнить несколько шагов, чтобы обеспечить максимальную безопасность .

  • Проверить отправителя
  • Подтвердить сообщение
  • Обработать сообщение

Отправитель всегда должны быть проверены, чтобы убедиться, что сообщение получено от доверенного отправителя. После этого само сообщение должно быть проверено, чтобы убедиться, что ничего не получено. После этих двух проверок сообщение может быть обработано.

Общение между окнами

Политика «Одинакового источника» (Same Origin) ограничивает доступ окон и фреймов друг к другу.

Идея заключается в том, что если у пользователя открыто две страницы: john-smith.com и gmail.com , то у скрипта со страницы john-smith.com не будет возможности прочитать письма из gmail.com . Таким образом, задача политики «Одинакового источника» – защитить данные пользователя от возможной кражи.

Политика "Одинакового источника"

Два URL имеют «одинаковый источник» в том случае, если они имеют совпадающие протокол, домен и порт.

Эти URL имеют одинаковый источник:

  • http://site.com
  • http://site.com/
  • http://site.com/my/page.html

А эти – разные источники:

  • http://www.site.com (другой домен: www. важен)
  • http://site.org (другой домен: .org важен)
  • https://site.com (другой протокол: https )
  • http://site.com:8080 (другой порт: 8080 )

Политика «Одинакового источника» говорит, что:

  • если у нас есть ссылка на другой объект window , например, на всплывающее окно, созданное с помощью window.open или на window из <iframe> и у этого окна тот же источник, то к нему будет полный доступ.
  • в противном случае, если у него другой источник, мы не сможем обращаться к его переменным, объекту document и так далее. Единственное исключение – объект location : его можно изменять (таким образом перенаправляя пользователя). Но нельзя читать location (нельзя узнать, где находится пользователь, чтобы не было никаких утечек информации).

Доступ к содержимому ифрейма

Внутри <iframe> находится по сути отдельное окно с собственными объектами document и window .

Мы можем обращаться к ним, используя свойства:

  • iframe.contentWindow ссылка на объект window внутри <iframe> .
  • iframe.contentDocument – ссылка на объект document внутри <iframe> , короткая запись для iframe.contentWindow.document .

Когда мы обращаемся к встроенному в ифрейм окну, браузер проверяет, имеет ли ифрейм тот же источник. Если это не так, тогда доступ будет запрещён (разрешена лишь запись в location , это исключение).

Для примера давайте попробуем чтение и запись в ифрейм с другим источником:

Код выше выведет ошибку для любых операций, кроме:

  • Получения ссылки на внутренний объект window из iframe.contentWindow
  • Изменения location .

С другой стороны, если у ифрейма тот же источник, то с ним можно делать всё, что угодно:

Событие iframe.onload – по сути то же, что и iframe.contentWindow.onload . Оно сработает, когда встроенное окно полностью загрузится со всеми ресурсами.

…Но iframe.onload всегда доступно извне ифрейма, в то время как доступ к iframe.contentWindow.onload разрешён только из окна с тем же источником.

Окна на поддоменах: document.domain

По определению, если у двух URL разный домен, то у них разный источник.

Но если в окнах открыты страницы с поддоменов одного домена 2-го уровня, например john.site.com , peter.site.com и site.com (так что их общий домен site.com ), то можно заставить браузер игнорировать это отличие. Так что браузер сможет считать их пришедшими с одного источника при проверке возможности доступа друг к другу.

Для этого в каждом таком окне нужно запустить:

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

Ифрейм: подождите документ

Когда ифрейм – с того же источника, мы имеем доступ к документу в нём. Но есть подвох. Не связанный с кросс-доменными особенностями, но достаточно важный, чтобы о нём знать.

Когда ифрейм создан, в нём сразу есть документ. Но этот документ – другой, не тот, который в него будет загружен!

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

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

Как поймать момент, когда появится правильный документ?

Можно проверять через setInterval :

Коллекция window.frames

Другой способ получить объект window из <iframe> – забрать его из именованной коллекции window.frames :

  • По номеру: window.frames[0] – объект window для первого фрейма в документе.
  • По имени: window.frames.iframeName – объект window для фрейма со свойством name="iframeName" .

Ифрейм может иметь другие ифреймы внутри. Таким образом, объекты window создают иерархию.

Навигация по ним выглядит так:

  • window.frames – коллекция «дочерних» window (для вложенных фреймов).
  • window.parent – ссылка на «родительский» (внешний) window .
  • window.top – ссылка на самого верхнего родителя.

Можно использовать свойство top , чтобы проверять, открыт ли текущий документ внутри ифрейма или нет:

Атрибут ифрейма sandbox

Атрибут sandbox позволяет наложить ограничения на действия внутри <iframe> , чтобы предотвратить выполнение ненадёжного кода. Атрибут помещает ифрейм в «песочницу», отмечая его как имеющий другой источник и/или накладывая на него дополнительные ограничения.

Существует список «по умолчанию» ограничений, которые накладываются на <iframe sandbox src=". "> . Их можно уменьшить, если указать в атрибуте список исключений (специальными ключевыми словами), которые не нужно применять, например: <iframe sandbox="allow-forms allow-popups"> .

Другими словами, если у атрибута "sandbox" нет значения, то браузер применяет максимум ограничений, но через пробел можно указать те из них, которые мы не хотим применять.

Вот список ограничений:

allow-same-origin "sandbox" принудительно устанавливает «другой источник» для ифрейма. Другими словами, он заставляет браузер воспринимать iframe , как пришедший из другого источника, даже если src содержит тот же сайт. Со всеми сопутствующими ограничениями для скриптов. Эта опция отключает это ограничение. allow-top-navigation Позволяет ифрейму менять parent.location . allow-forms Позволяет отправлять формы из ифрейма. allow-scripts Позволяет запускать скрипты из ифрейма. allow-popups Позволяет открывать всплывающие окна из ифрейма с помощью window.open .

Больше опций можно найти в справочнике.

Пример ниже демонстрирует ифрейм, помещённый в песочницу со стандартным набором ограничений: <iframe sandbox src=". "> . На странице содержится JavaScript и форма.

Обратите внимание, что ничего не работает. Таким образом, набор ограничений по умолчанию очень строгий:

Что нужно проверять чтобы postmessage был безопасным

The window.postMessage() method safely enables cross-origin communication between Window objects; e.g., between a page and a pop-up that it spawned, or between a page and an iframe embedded within it.

Normally, scripts on different pages are allowed to access each other if and only if the pages they originate from share the same protocol, port number, and host (also known as the «same-origin policy»). window.postMessage() provides a controlled mechanism to securely circumvent this restriction (if used properly).

Broadly, one window may obtain a reference to another (e.g., via targetWindow = window.opener ), and then dispatch a MessageEvent on it with targetWindow.postMessage() . The receiving window is then free to handle this event as needed. The arguments passed to window.postMessage() (i.e., the “message”) are exposed to the receiving window through the event object.

Contents

Syntax

    (to spawn a new window and then reference it), (to reference the window that spawned this one), (to reference an embedded <iframe> from its parent window), (to reference the parent window from within an embedded <iframe> ), or + an index value (named or numeric).

The dispatched event

A window can listen for dispatched messages by executing the following JavaScript:

The properties of the dispatched message are:

Security concerns

If you do not expect to receive messages from other sites, do not add any event listeners for message events. This is a completely foolproof way to avoid security problems.

If you do expect to receive messages from other sites, always verify the sender’s identity using the origin and possibly source properties. Any window (including, for example, http://evil.example.com ) can send a message to any other window, and you have no guarantees that an unknown sender will not send malicious messages. Having verified identity, however, you still should always verify the syntax of the received message. Otherwise, a security hole in the site you trusted to send only trusted messages could then open a cross-site scripting hole in your site.

Always specify an exact target origin, not * , when you use postMessage to send data to other windows. A malicious site can change the location of the window without your knowledge, and therefore it can intercept the data sent using postMessage .

Secure shared memory messaging

If postMessage() throws when used with SharedArrayBuffer objects, you might need to make sure you cross-site isolated your site properly. Shared memory is gated behind two HTTP headers:

    with same-origin as value (protects your origin from attackers) with require-corp as value (protects victims from your origin)

To check if cross origin isolation has been successful, you can test against the crossOriginIsolated property available to window and worker contexts:

See also Planned changes to shared memory which is starting to roll out to browsers (Firefox 79, for example).

Example

Notes

Any window may access this method on any other window, at any time, regardless of the location of the document in the window, to send it a message. Consequently, any event listener used to receive messages must first check the identity of the sender of the message, using the origin and possibly source properties. This cannot be overstated: Failure to check the origin and possibly source properties enables cross-site scripting attacks.

As with any asynchronously-dispatched script (timeouts, user-generated events), it is not possible for the caller of postMessage to detect when an event handler listening for events sent by postMessage throws an exception.

postMessage() schedules the MessageEvent to be dispatched only after all pending execution contexts have finished. For example, if postMessage() is invoked in an event handler, that event handler will run to completion, as will any remaining handlers for that same event, before the MessageEvent is dispatched.

The value of the origin property of the dispatched event is not affected by the current value of document.domain in the calling window.

For IDN host names only, the value of the origin property is not consistently Unicode or punycode; for greatest compatibility check for both the IDN and punycode values when using this property if you expect messages from IDN sites. This value will eventually be consistently IDN, but for now you should handle both IDN and punycode forms.

The value of the origin property when the sending window contains a javascript: or data: URL is the origin of the script that loaded the URL.

Using window.postMessage in extensions ‘

window.postMessage is available to JavaScript running in chrome code (e.g., in extensions and privileged code), but the source property of the dispatched event is always null as a security restriction. (The other properties have their expected values.)

It is not possible for content or web context scripts to specify a targetOrigin to communicate directly with an extension (either the background script or a content script). Web or content scripts can use window.postMessage with a targetOrigin of «*» to broadcast to every listener, but this is discouraged, since an extension cannot be certain the origin of such messages, and other listeners (including those you do not control) can listen in.

Content scripts should use [[../../../../Mozilla/Add-ons/WebExtensions/API/runtime|runtime.sendMessage]] to communicate with the background script. Web context scripts can use custom events to communicate with content scripts (with randomly generated event names, if needed, to prevent snooping from the guest page).

Lastly, posting a message to a page at a file: URL currently requires that the targetOrigin argument be «*» . file:// cannot be used as a security restriction; this restriction may be modified in the future.

Читать:
Как закомментировать несколько строк в pycharm

Похожие статьи