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

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

  • автор:

Window.postMessage()

Window.postMessage() — этот метод позволяет безопасно отправлять кроссдоменные запросы. Обычно сценариям на разных страницах разрешён доступ друг к другу только если страницы, которые их выполняли, передаются по одному протоколу (обычно это https), номер порта (443 — по умолчанию для https) и хост (modulo Document.domain установленный страницами на одно и тоже значение). window.postMessage() предоставляет контролируемый механизм, чтобы обойти это ограничение способом, который безопасен при правильном использовании.

При вызове метода window.postMessage() он вызывает MessageEvent (en-US) для отправки в целевом окне, когда завершается любой ожидающий сценарий, который должен быть выполнен (например, оставшиеся обработчики событий, если window.postMessage() вызывается из обработчика событий ранее заданных ожидающих таймаутов). MessageEvent (en-US) имеет тип message , data-свойство которого устанавливает значение первого аргумента в методе window.postMessage() , свойство origin соответствует адресу основного документа в вызове window.postMessage во время вызова window.postMessage() , свойство source указывает на окно, из которого window.postMessage() вызвали. (Другие стандартные свойства событий имеют ожидаемые значения)

Syntax

Ссылка на другое окно; такая ссылка может быть получена, к примеру, при использовании свойства contentWindow элемента iframe , объекта, возвращаемого window.open (en-US) , или по именованному и числовому индексу Window.frames , если вы пытаетесь запустить сообщение из iframe в родительском окне, то родитель также является действительной ссылкой.

Данные, которые нужно отправить в другое окно. Данные сериализуются с использованием алгоритма структурированного клона. Это означает, что вы можете безопасно передавать большое количество объектов данных в окно назначения без необходимости их сериализации. [1]

Specifies what the origin of otherWindow 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 otherWindow ‘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.

Is 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.

The dispatched event

В otherWindow отправляемые сообщения могут быть обработаны следующим способом:

Свойства отправляемых сообщений:

Объект, переданный из другого окна.

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.

Ссылка на объект window (en-US) , который отправил сообщение; может быть использована для установки двустороннего соединения между окнами с разными origins .

Вопросы безопасности

Если вы не ожидаете получения сообщения от других сайтов, не добавляйте обработчики событий message . Это гарантированный способ избежать проблем с безопасностью.

Если же вы хотите получать сообщения от других сайтов, то всегда необходимо идентифицировать отправителя, используя origin и возможно source свойства. Любой сайт (включая, например, http://evil.example.com ) может отправлять сообщения любым другим, и у вас нет гарантии, что неизвестный отправитель не пошлёт вредоносные сообщения. Однако даже если отправитель известен, вам всё равно необходимо всегда подтверждать синтаксис получаемого сообщения. Иначе, дыра в безопасности сайта, которому вы доверяете, может открыть дыру для межсайтового скриптинга на вашем сайте.

Всегда конкретизируйте целевой первоисточник, а не просто * , когда вы используете postMessage для отправки данных другим окнам. Вредоносный сайт может изменить локацию окна без вашего ведома и затем перехватить данные, посылаемые с использованием postMessage .

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.

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.

How to avoid receiving postMessages from attackers ?

PostMessage is a JavaScript API that enables cross-origin communication between web pages. While it is a useful feature, it can also be a security concern if not handled properly. Attackers can use postMessage to perform malicious actions, such as stealing sensitive information or injecting scripts into the page.

To avoid receiving postMessages from attackers, there are several best practices that can be followed:

  1. Origin validation: Verify that the sender of the postMessage is from a trusted origin by checking the event.origin property. Only accept postMessages from known and trusted origins. This can be done by comparing the origin of the sender against a list of allowed origins.
  2. Use event.source: Verify that the sender of the postMessage is a valid window object by checking the event.source property. Only accept postMessages from known and trusted window objects.
  3. Use targetOrigin:When sending postMessages, use the targetOrigin parameter to specify the origin of the recipient. This will ensure that the postMessage is only delivered to the intended recipient.
  4. Use a token-based authentication mechanism: In addition to origin validation, you can use a token-based authentication mechanism to ensure that the postMessage is coming from a trusted source. For example, you can generate a unique token for each valid sender and include it in the postMessage. The recipient can then verify the token before processing the postMessage.
  5. Sanitize the data:Before you process the postMessage, sanitize the data to ensure that it is safe to use. This can include checking for and removing any potentially dangerous characters or scripts.
  6. Use Content Security Policy (CSP): CSP is a security feature that helps to detect and mitigate certain types of attacks, including Cross-Site Scripting (XSS) and data injection attacks. CSP can be used to prevent the browser from executing any scripts that are not explicitly allowed by the policy.

It’s important to keep in mind that there is no 100% foolproof way to protect against postMessage attacks, but using a combination of these methods can significantly reduce the risk. Keep your system and software updated, and it’s also important to stay up-to-date with the latest security best practices and to test your application for vulnerabilities on a regular basis.

In summary, postMessage is a powerful JavaScript API that enables cross-origin communication between web pages. However, it is important to handle it properly to avoid security concerns. By using origin validation, event.source, targetOrigin, token-based authentication, data sanitization, and Content Security Policy, you can greatly reduce the risk of receiving postMessages from attackers.

Sure, here are some examples of how to implement some of the postMessage security best practices:

jedp / gist:3005816

The postMessage() API is an HTML5 extension that permits string message-passing between frames that don’t share the same origin. It is available in all modern browsers. It is not supported in IE6 and IE7.

postMessage is generally considered very secure as long as the programmer is careful to check the origin and source of an arriving message. Acting on a message without verifying its source opens a vector for cross-site scripting attacks. See Zalewski [4].

For some historical background, Barth et al. [3] describe prior cross-frame communication hacks. Section 4.2 explains how the origin parameter patches XSS vulnerabilities. Without the origin parameter, an attacker could cause a child frame engaged in message-passing with the parent to navigate away to a different site, with the result that the message could be delivered to the attacker.

Checklist for postMessage Security Review

Based on the considerations described in the References below, here is a checklist for assessing uses of postMessage() :

JS — How to securely use window.postMessage when the sender domain is unknown

I would like to create a secure postMessage connection (origin safe), with an Iframe that is created at runtime.

Current state: I have a script, that generates an iframe with a specific domain ( domain.b.com in the example below). I want that iframe to receive messages only from the parent domain (the page that included my script). Since the parent domain is unknown at runtime, I’m thinking of a «Handshake» process as described and illustrated below:

  1. Wait for Iframe to be loaded.
  2. Send postMessage from the parent domain with it’s origin.
  3. Set the allowed origin to be the 1st received origin

Edit: More Info:

  1. On my server I have a whitelist domains (for example domain.a.com, any.domain.com, domain.b.com)
  2. My Goal is to integrate with some of my clients (for example domain.a.com , domain.b.com)
  3. Once integrated I want to prevent hackers injecting Iframes that can listen to sensitive information over postMessage
  4. I want to avoid checking the whitelist, I prefer to give some acessToken, but not sure what is the right flow.

Example 1:

enter image description here

Example 2:

enter image description here

Is that the right way to implement it?

1 Answer 1

As mentioned here, you should not expect the parent’s origin to be sent to you in postMessage ‘s parameter. Instead:

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.

And once you have the main frame’s URI in your iframe, you can verify its authorization with a simple AJAX call to the server. In my point of view, a server call is inevitable and one way or another you will make such a call.

There are other ways to know who is including your iframe but they are not relying on postMessage . For instance if you are using PHP, you can check $_SERVER[‘HTTP_REFERER’] to see who is requesting your iframe even before it is sent to the browser. Yet there are ways to referrer spoofing as well.

If your application requires a solid bullet proof solution then server to server communication is your way. In this scenario, each client of yours has a username and password and the web server who is going to serve the main page should ask for a one time pass token from the web server who is serving the iframe (this is a server to server communication). And then use the token in the iframe’s URL to be sent back to the server generated it. Here’s a step by step of this scenario:

End user asks for the URL http://customer.com/main.php .

While main.php is executing and populating the response, it also connects to http://you_website.com/generate_token.php?username=cutomer1&password=123 and gets a one time pass token token1 .

The response is returned to the browser containing an iframe with URL http://your_website.com/iframe.php?token=token1 .

In iframe.php you verify the token1 to see if it is valid, and , at the same time, you are authenticating the requester without actually asking for his username and/or password (since you know who you have generated the token for).

Such tokens are usually deleted once used (one time pass) and they also usually come with an expiration data. But that’s up to you and your application.

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

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