Link Search Menu Expand Document

Unchecked Origin in postMessage

  1. Unchecked Origin in postMessage
    1. Description
    2. Impact
    3. Prevention
    4. Testing
    5. References

Description

postMessage is a way to perform safe (if done properly) cross-origin communication between JavaScript Window objects. This mechanism comprises two parts:

The sender uses the targetWindow.postMessage(message, targetOrigin) to send a message to the targetWindow but only if the origin in that window matches targetOrigin (or if targetOrigin is set to the special value *);

The receiver listens for the message event in the window object.

Problems arise when, due to unforeseen circumstances, legitimate code (either sent or received) communicates with an untrusted party.

Impact

Suppose the sender doesn’t accurately check the origin. In that case, they might end up disclosing sensitive data to a malicious origin. In contrast, the receiver might end up performing actions on the target origin, albeit originating from the attacker origin. The actual impact really depends on what the vulnerable web application can do. This does, of course, mean that a high-value vulnerable web application with ineffective and permissive postMessage controls may represent a significant risk.

Prevention

The sender must always literally specify the targetOrigin instead of designating a wildcard *. Similarly, the receiver must check the origin of the window sending the message which is passed via the event.origin property. A common mistake is to perform too lax checks on the origin. For example, suppose in, say, a Node.js application, the allowed origin is http://safe.example.com, and the check is implemented like the following:

addEventListener('message', (event) => {
    if (event.origin.match(/safe.example.com/)) {
        // do sensible stuff...
    };
});

The above implementation has at least two accidents waiting to happen. The first and most glaring is that an attacker could register safe.example.com.attacker.com and bypass the check. The second is that . is a special character in regular expressions, so for example safeXexample.com also matches /safe.example.com/. The preferred solution is to check the allowed origins against a list:

addEventListener('message', (event) => {
    if (event.origin === 'https://safe.example.com') {
        // do sensible stuff...
    };
});

Testing

Verify the origin of incoming web messages and treat them as untrusted data by verifying their validity.

References

MDN - Window.postMessage()

Detectify Labs - The pitfalls of postMessage