Before we dive into the vulnerabilies posed by
The browser enforces a Same Origin Policy which prevents websites from attacking each other. Suppose that you are an attacker who has set up a phishing page, on which you make a get request to
https://examplebank.com/userAccount/getAccountInformation.aspx . Let's say a victim visiting your website is logged into this bank, the default behaviour for the browser is to always include the cookies of a website in a request made to it. Since the victim is logged in, the page getAccountInformation.aspx will return the user's information in it's response. Now if the Same Origin Policy didn't exist, the attacker hosting the phishing page can simple load the "getAccountInformation.aspx" page in an invisible iframe on the victim's browser and read the data returned by it.
According to PortSwigger:
The same-origin policy restricts scripts on one origin from accessing data from another origin. An origin consists of a URI scheme, domain and port number. For example, consider the following URL:
http, domain(including subdomain):
normal-website.comand the port number:
8080, form an origin for this page and all the three things must be same for any other URI to be considered to be from the same origin. The same origin policy will prevent any page from another origin to read the contents of this page and vice versa. Now that we know what the SOP(Same Origin Policy) is, we can begin to see why
postMessagecame into existence.
targetOrigin specifies the origin that the message is intended for and
transfer is a sequence of Transferable Objects.
In short, postMessage is a secure way to circumvent the same origin policy ... or is it?
Now that we have an understanding of how and why the
postMessage function is used, we have reached the fun part of this blog - Exploiting it!
Using postMessage is one of the ways that two cross origin web pages can communicate with each other, moreover developers fail to understand the implications that a vulnerability of cross origin messaging can entail. So let us look at some common pitfalls:
The target Origin is required to be set to a specific origin that is intended receiver of the message. But it's a common and dangerous mistake for developers to include a wildcard
* in place of targetOrigin, which will allow any origin to access the messages which is harmful if the message includes any sensitive data. An example scenario can be seen below:
Suppose, that page at
https://somewebsite.com embeds a child window or an iframe with an origin
http://sub.somewebsite.com , which sends a postMessage which was supposedly intended for
http://somewebsite.com , but the developer made this mistake of specifying
* wildcard as the targetOrigin:
http://somewebsite.com does not have X-Frame-Header protection set...an attacker can host a malicious webpage exploiting this behaviour by changing the location of the window object in the iframe loaded by
Let's understand this one line at a time:
exp to be executed after 6s. The delay is to make sure that the iframe is properly loaded.
exp function further sets up a logic to change the location of the iframe object which will set it's origin to the attacker's domain.
Now the postMessage meant for
somewebsite.com will instead be sent to the attacker controlled domain. A detailed description of a bug found in the wild on docs.google.com can be found here.
In the receiving end of the messages, the window sets up a listener for 'message' events and registers the function responsible for handling messages received.
In this above code, the function registered for handling messages does a check or validation to ensure that the message it is about to process has originated from a trusted domain, which is really important before any sensitive action, such as updating user's information or processing a payment is performed based on that data. An example to demonstrate this:
As we can see in the above snippet, no validation on the data is being performed before using it to change the innerHTML of a web page, this can lead to an attacker embedding the webpage in iframe and sending an XSS payload which can steal all the user's data logged in to the site.
The best way to spot postMessage vulnerabilities is to look out for the event listeners for 'message' event which can be spotted by
onMessage and addEventListener('message', ...)
Such a check can be easily bypassed by registering a subdomain like :
https://legitimate.com.attacker.site which is still an attacker controlled website.
Such a check can be bypassed easily by just passing a domain as
legit.matesite.com where the
. will match a single character as it got converted to a regex and
legit.matesite will match with
This bypass can be achieved by framing our own page within a sandboxed iframe which sets the origin of the iframe to
null, We also need to set the allow-popups tag which will make all the popups inherit all the sandboxed attributes, i.e. the origin will be again set to
This will cause both the
e.origin == window.origin == null and bypass the check.
Some headers like
X-Frame-Header can prevent a webpage from getting iframed. In such you can open a new tab to the vulnerable web application and communicate with it: