The application uses the window.postMessage () method to allow cross-origin communication between different window objects. This method provides a way to circumvent the Same Origin Policy restrictions.
Typically, scripts on different pages can access each other only if the pages from which they originate share the same protocol, port number, and host (also known as “same-origin policy”). window.postMessage () provides a controlled mechanism to bypass this restriction
Generally speaking, a window can get a reference to another (for example, via targetWindow = window.opener) and then send a MessageEvent on it with targetWindow.postMessage (). The reception window is free to handle this event as needed. The arguments passed to window.postMessage () (that is, the “message”) are exposed to the receiving window through the event object.
Syntax:
The two required components are,
The syntax for the postMessage() method is
targetWindow.postMessage(message, targetOrigin, [transfer]);
There is an optional third parameter, [transfer], that we will not be using. You may want to read more about the MDN.
Example
We will create two web pages called Page1.html and Page2.html. Page2.html will be a popup window.
Create the following files
Page1.html (note the sendMessage function)
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset=”utf-8″ />
<script>var childwin;
const childname = “popup”;
function openChild() {childwin = window.open(‘Page2.html’, childname, ‘height=300px, width=500px’);
}
function sendMessage(){
let msg={pName : “alice”, pAge: “23”};
// In production, DO NOT use ‘*’, use toe target domain
childwin.postMessage(msg,’*’)// childwin is the targetWindow
childwin.focus();
}</script>
</head>
<body>
<form>
<fieldset>
<input type=’button’ id=’btnopen’ value=’Open child’ onclick=’openChild();’ />
<input type=’button’ id=’btnSendMsg’ value=’Send Message’ onclick=’sendMessage();’ />
</fieldset>
</form>
</body>
</html>
Page2.html (note callback function in addEventListener)
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset=”utf-8″ />
<script>// Allow window to listen for a postMessage
window.addEventListener(“message”, (event)=>{// Normally you would check event.origin
// To verify the targetOrigin matches
// this window’s domain
let txt=document.querySelector(‘#txtMsg’);
// event.data contains the message sent
txt.value=`Name is ${event.data.pName} Age is ${event.data.pAge}` ;
});function closeMe() {
try {window.close();
} catch (e) { console.log(e) }
try {self.close();
} catch (e) { console.log(e) }}
</script>
</head>
<body>
<form>
<h1>Recipient of postMessage</h1>
<fieldset>
<input type=’text’ id=’txtMsg’ />
<input type=’button’ id=’btnCloseMe’ value=’Close me’ onclick=’closeMe();’ />
</fieldset>
</form>
</body>
</html>
Test Run
Open Page1.html and click the “Open child” button. This opens the pop-up.
Popup-targetWindow
Click the “Send Message” button. The message is received by the pop-up window.
Result of childwin.postMessage()
postMessage () must be implemented correctly; Otherwise, it may lead to security vulnerabilities such as Cross-Site Scripting (XSS), Exposure of sensitive data, Information theft and others.
Detecting these vulnerabilities is not very simple. It requires knowledge and understanding of JavaScript to read the JavaScript of the target application to identify possible points of attack. It is necessary to trace the flow of execution to perform a successful attack.
To exploit postMessage () vulnerabilities, you first need to know whether the target application is using web messaging or not. If the target application uses web messaging, it is essential to identify the different listeners. There are several methods to do this, including:
HTML5 postMessage introduces a new source of corruption in the form of the message payload (Event.data). A DOM-based Cross-Site Scripting (XSS) vulnerability occurs when the payload of a message event is handled insecurely. The following table lists some of the more common functions and attributes that can lead to an XSS vulnerability.
Function | Description |
document.write({taint}) document.writeln({taint}) | The document.write function writes the string passed to the page, including any embedded script code. To exploit this function, the attacker simply embeds the script code within the tainted input. |
element.innerHTML={taint} element.outerHTML={taint} | Similar to document.write, setting the innerHTML or externalHTML attributes with a tainted value can be exploited by embedding malicious script code within the assigned value. |
location={taint} location.href={taint} window.open({taint}) location.replace({taint}) | Changing the location of the page could be exploited to perform an XSS attack by passing a JavaScript: or Data: protocol handler such as the value. For instance, location = “JavaScript:alert(‘xss’)” location = “data:text/html, <script>alert(document.cookie)</script>” |
$({taint}) | Markup that is passed directly to a jQuery selector is evaluated immediately, and any embedded JavaScript event handlers are executed. For instance; $(“<svg onload=’alert(123)’>”)// Executes alert(123) |
eval({taint}) | The data passed to the eval () function is evaluated as JavaScript, therefore if the attacker can control the data passed to this function, it is possible to perform XSS. |
ScriptElement.src ScriptElement.text ScriptElement.textContent ScriptElement.innerText | Setting the “src” attribute of a script element allows a script to be loaded from an attacking controller server. Setting the text, textContent or innerText allows the content of the script will be modified. |
Href,srcattribute of various elements. | Many elements that support an “href” or “src” attribute can be exploited to perform an XSS attack by setting a JavaScript: or Data: URI. Some examples include; TEXT, EMBED, OBJECT, A, and IFRAME, however, this is not an exhaustive list and new elements are introduced over time. |
Use postMessage for multi-threaded applications, and it allows to securely communicating between threads via their created windows. postMessage( ) sends data locally between the Window objects without generating an HTTP request. It is used for DOM-based communication.