In part two of our series, we take a deeper dive into how JavaScript works and its implications to web and e-commerce security and compliance. This demonstration will not surprise anyone with a deep understanding of how browsers and JavaScript function; however, for those less technical we hope this article will increase your understanding of risks you may not have anticipated.
Let's look at two important e-commerce risks (1) Form Eavesdropping, and (2) HTML Modification.
When you visit a website, your browser downloads a local copy of the webpage in what is called the Document Object Model (DOM). This includes HTML tags, styles, forms, content, links to other sites, and JavaScript. It also downloads any third-party website code included by the main page or any included page. You see the page but behind the scenes, your browser has built everything from many sources. The JavaScript provides the dynamic nature of web pages that gives many websites a magic quality.
JavaScript is extremely powerful because it has the ability to edit the DOM (i.e. your local copy of the webpage) and add or modify virtually any element of the webpage at any event (e.g. mouse click) or time of the programmers choice. To put it another way, a third-party JavaScript can rewrite your webpage in your customers browser and, because it happens in the customers local copy, you will not know about it. This is how JavaScript can be used maliciously.
For this article, we constructed several simple web pages using HTML and JavaScript to illustrate how Form Eavesdropping and HTML Modification works. These examples are intentionally minimalistic, uncluttered, self-contained, and designed to prove specific points quickly. You can click on the links provided or download the code and run it from your local disk. The source is fully transparent so that you can get easily understand how it works.
These examples are not intended to be sophisticated skimmers like those used by criminals. Rather, these examples demonstrate some of the basic techniques that e-commerce skimmers often implement.
We aren’t giving away any secrets by showing you this. Criminals, malicious actors, and many security practitioners already know this. We’re simply raising awareness of these threats to start a long-needed conversation about the implications of this functionality for security, privacy, and compliance.
Web forms are used to collect everything from usernames and passwords, to sensitive personal information, credit card account information, and more. While these forms are familiar to everyone, most people are unaware of just how potentially exposed this information is. The contents entered into a web form is visible to any code running inside the same DOM. This means every line of JavaScript, including JavaScript linked from third-party websites has the ability to access data you entered. This functionality is used by analytics and web replay software. It is also a common method to steal credit card data.
The example below has two data entry forms that use DuckDuckGo’s search engine. Both forms are identical except for the name field. Both forms pop a new tab and run the search:
<form action="https://duckduckgo.com/" method="post" target="_blank" name="S2">
<label for="stext">Search Text:</label><br>
<input type="search" name="q">
<input type="submit" value="Search">
</form>
You will also find a small script that implements the form snooping technique. Its function is to silently find and modify the entry form in the DOM. When you click on submit, the script grabs the input and writes it below the form – like some slightly creepy browser history. Of course, a skimmer would grab more data and send it off (encoded) to the criminals instead of showing you.
const forms = document.querySelectorAll('form')
forms.forEach(f => {
if (f.name === 'S2') {
f.onsubmit = (e) => {
let injectedNodes = document.querySelectorAll(".injected") || []
let p = document.createElement("p")
p.className = "injected"
p.style = "margin:0;"
p.innerHTML = `${injectedNodes.length + 1}. Why are you interested in <strong>${e.target.elements.namedItem("q").value} </strong>?`
document.getElementById("Q2").append(p)
}
}
})
The script goes through the DOM looking for a specific named form, "S2", and then extracts the value of the query parameter "q".
To minimize this risk, web sites often use IFRAMEs for the form entry fields which allows them to limit visibility of the data to a separate DOM and hopefully minimize exposure to unwanted JavaScript and third-party code. This is the main point of PCI's guidance on the risk and scope for shopping carts vs. payment pages.
You can try this demo at URL https://controlgap.github.io/pci_magecart_dom/PCI-Magecart-Dom-Form_Script-1.html
Now what if we told you that those same third party JavaScripts can effectively modify hard-coded links in your web page? While the script can’t change the source page on your server, it can change the downloaded copy inside the DOM in your customers browser. That means the link to your IFRAME or other URL can be changed! Our demo page has two simple hard-coded links that are displayed inside a new tab:
<a href="https://www.controlgap.com/blog" target="_blank">Click here for the controlgap blog - no surprises</a>
<a href="https://www.wikipedia.org/" target="_blank">Click here to go to Wikipedia - and a surprise</a>
There is also a small script that rewrites URLs. Any html A-tag referencing Wikipedia will be changed to a spoof site:
function URLsuprise() {
const links = document.querySelectorAll('a')
links.forEach((a) => {
if (a.href.includes('www.wikipedia.org')) {
a.href = 'https://en.uncyclopedia.co/'
}
})
}
URLsuprise()
This script looks for a link with a specific href value and changes it.
This simple example has a few obvious problems. While viewing the source shows Wikipedia, the DOM inspector and simply hovering your mouse over the link shows the deception.
You can try this demo at URL https://controlgap.github.io/pci_magecart_dom/PCI-Magecart-Dom-URL_Script-2.html
We also wanted to provide a more sophisticated example. In this example, the script hooks all HTML address tags (A-tags) and makes the change temporary when the link is clicked.
const links = document.querySelectorAll('a');
links.forEach((a) => {
a.onclick = (e) => {
const oldLink = e.target.href;
if (oldLink.includes("wikipedia.org")) {
e.preventDefault();
e.stopPropagation();
e.target.href = 'https://en.uncyclopedia.co/';
e.target.click();
e.target.href = oldLink;
}
}
})
This script changes the link's HREF only while it is being clicked on.
This version of the script is more deceptive, the original Wikipedia URL is also displayed when you use the DOM inspector and when you hover your mouse over the link.
You can try this demo at URL https://controlgap.github.io/pci_magecart_dom/PCI-Magecart-Dom-URL_Script-3.html
We also ran the same code through an obfuscator to demonstrate a common concealment technique.
const _0x53f3 = ['wikipedia.org', 'click', 'target', 'href', 'onclick', 'preventDefault', 'stopPropagation', 'forEach', 'includes'];
(function (_0x391e4e, _0x53f305) { const _0x29a541 = function (_0x378353) { while (--_0x378353) { _0x391e4e['push'](_0x391e4e['shift']()); } };
_0x29a541(++_0x53f305); }(_0x53f3, 0x154)); const _0x29a5 = function (_0x391e4e, _0x53f305) { _0x391e4e = _0x391e4e - 0x0; let _0x29a541 = _0x53f3[_0x391e4e]; return _0x29a541; };
const links = document['querySelectorAll']('a'); links[_0x29a5('0x0')](_0xc5942e => { _0xc5942e[_0x29a5('0x6')] = _0x19a759 => { const _0xaaf3b3 = _0x19a759['target'][_0x29a5('0x5')];
_0xaaf3b3[_0x29a5('0x1')](_0x29a5('0x2')) && (_0x19a759[_0x29a5('0x7')](), _0x19a759[_0x29a5('0x8')](), _0x19a759[_0x29a5('0x4')][_0x29a5('0x5')] = 'https://en.uncyclopedia.co/',
_0x19a759[_0x29a5('0x4')][_0x29a5('0x3')](), _0x19a759[_0x29a5('0x4')][_0x29a5('0x5')] = _0xaaf3b3); }; });
Consider the following security thought experiment in the context of the previous two types of attack. Here are the parameters:
The target system is a merchant shopping cart
In short, there should be no way for an attacker to modify the merchant or processor systems.
In our opinion, the examples above have alarming security and privacy implications. The JavaScript HTML modification risk is particularly bothersome and suggests that there is a requirement for be some mechanism(s) or process(es) that addresses the risk from third-party provided code.
We’ve conducted many reviews of e-commerce systems and it’s clear from our experience that a significant number of organizations and many developers are unaware of these risks. A large percentage of e-commerce sites still use direct post forms and rely upon dozens of third-party scripts. They’re often shocked by their PCI DSS compliance footprint that a simple IFRAME can reduce. Fewer still are addressing the risks of HTML modification.
Our QSA and Offensive Security teams are happy to assist you with any security and compliance concerns you may have.