In this month’s blog, we interviewed Neil Bell, a computer scientist and security researcher from UC Berkeley and University of Maryland Baltimore County, to get a download of how Javascript is useful and how it can go terribly wrong in the wrong hands.
Javascript: The Good
The ability to inject Javascript into websites is critical for advertising and analytics companies such as HDMZ to identify and measure audience visits by leveraging normal browser code execution when a website is loaded. In most cases, an approved and trustworthy partner, such as Google Analytics, refines and publishes a Javascript snippet that enables benign visitor-tracking identifiers to be reported back to a central system.
Diagram source: Mozilla.org
Functionally speaking, when a visitor loads a website, that request is routed through the internet to the appropriate webserver. The webserver generates content as intended, including any HTML and Javascript that the visitor experience requires, and ships it back to the requesting browser for it to be parsed and displayed. When Javascript originates from the requested domain and webserver, the browser generally treats it as “trusted”, executing it normally. However, trusted Javascript can also request and trigger execution of other Javascript code—which is where things can get interesting.
Let’s Break It Down
Google Analytics and a host of other common advertising and tracking mechanisms work by way of a complex and robust mesh of Javascript execution. In today’s Javascript-heavy internet, content returned by a webserver nearly always contains an HTML tag like the following:
<script type=’text/javascript’ src='https://some-domain/js/code_1234.js’ />
When this is received by the browser, the browser will attempt to fetch whatever is located at that “src” address and attempt to execute it as Javascript. In most cases this is expected and benign behavior, and everything works as intended.
As a sidebar, this is similar to how email “opens” are tracked, with the email client fetching remote images from a sender-controlled webserver using an HTML tag like the following:
<img src=’https://some-domain/img.jpg?id=1234’ />
In this case, the address contains the identifier “id=1234” which the receiving webserver parses and records as an opening of email #1234. The webserver then generally responds back with a pixel-sized image that doesn’t affect the rendering of the email. The email-receiving platform doesn’t distinguish this pixel from other graphics, and the human reader is none the wiser.
So, What’s The Catch?
Malicious Javascript injection refers to cases where a bad actor adds Javascript to a webpage with a non-standard, malicious intent. Consider a case where a bad actor hides a bitcoin-computing package within a default Google Analytics snippet. Visitors’ browsers would parse the website-provided Javascript tag as usual, automatically fetching and executing the “normal” Google Analytics commands, but also executing the malicious code behind the scenes, earning money for the author of the malicious code. Unfortunately, the bad actor may go one layer deeper to mask the Javascript-style fetch altogether, so that the malicious code itself is hosted on an external 3rd party actor-controlled server, effectively obfuscating the whole execution from Google’s fraud detection.
Based on the security settings of a visitor’s browser, and of the visited website, more significantly negative impacts can potentially occur. Browsers generally share cookies between opened tabs, which enables users to have different pages visible while still using the same logged-in browsing session. Consider a simplified scenario where a visitor logs into their bank’s website in one browser tab, and browses to a website infected with a Javascript injection in another tab. The injected Javascript could contain code like the following, known as cross-site request forgery (CSRF):
var http_request = new XMLHttpRequest();
http_request.open(“GET”, “https://bank-domain/transfer?target_account=12345678”);
http_request.send();
Poorly written bank websites, browsers enabling remote-site requests, and cross-session cookie sharing can allow malicious actors to automatically transfer funds from unsuspecting visitors to their own account. Granted, this is a contrived and simplified example, but it is not overly far-fetched given the actual freedom that browsers provide to embedded Javascript. Thankfully, browsers have evolved to a point where websites and their cookies are fairly isolated and sandboxed, reducing the likelihood of an attack like this working.
Source: https://xkcd.com/538/
This All Sounds Terrifying. Tell Us More.
Cross-site request forgery isn’t the only way arbitrary and unguarded Javascript execution can occur, however. Recall the days of MySpace, with Tom as a default friend for all new accounts. Tom was the co-founder of MySpace and the default behavior was to have his account automatically be “friends” with any new accounts on the platform. In 2005, however, an enterprising computer security researcher early in his experimental phase, wrote a specific Javascript snippet which automatically ran whenever someone viewed an infected profile, infecting that visitor’s profile unbeknownst to anyone involved. What resulted was the fastest spreading computer virus of all time, infecting over a million profiles in just 20 hours, causing the snippet to lodge itself in the victim’s profile and triggering a friend request to be sent back to the author. If left unmitigated, this attack would have seen the author challenging Tom’s reign as the most common friend due to the deep interconnected nature of the friendship network.
This virus was a type of Javascript injection called cross-site scripting (XSS), which revolves around the execution of Javascript provided unknowingly by a benign webserver. In the MySpace example, the author saved a custom snippet of Javascript to his profile in such a way that it would be executed along with any other Javascript when the profile was viewed. Thus, the snippet ran in each victim’s browser once delivered by the MySpace webserver, executing locally with the same local permissions and cookie access since it was part of the viewed page on the same MySpace domain.
Often these types of attacks can appear in forums and comment threads where a malicious actor enters something like this as a comment:
Yes, I totally agree! <script>alert(“infected!”);</script>
Without proper protections by the website author, subsequent views by other visitors would cause the alert popup to trigger. This is because the comment text is often interleaved with other HTML as if it was benign text. The browser would render the page as normal top to bottom, and when encountering this Javascript script tag, would execute it just as if it were the website author’s intended script and behavior. This style of attack is generally mitigated by a webserver filter catching and escaping script text before it’s displayed.
Escaping text upon rendering is the webserver’s way of ensuring that text entered is displayed truly as if it was plain text and nothing special. For example, the XSS Javascript shown above would instead be escaped by the webserver and sent to the browser as:
“<script>alert(“infected!”);</script>”
thus neutering the HTML tags. The browser will decode the “<” into “<” and “>” into “>”, and render the XSS attack as text on the page, plainly visible to other viewers, rather than treating “<script>” as the start of Javascript code.
Additional filtering allows only known and approved benign HTML tags to persist, such as embedded images or bold/underlining tags. This solution can be brittle, however, as many methods exist for obfuscating an XSS’ true nature. Fortunately, the Open Web Application Security Project (OWASP) has a published set of XSS techniques which can be studied and mitigated.
In summary, Javascript injection serves a great purpose for companies to know their visitors and provide seamless and smooth interactions, but also it can potentially provide a vector for malicious actors to gain a foothold with negative repercussions. Website designers, browser developers, and advertising companies all share an ethical responsibility to keep their visitors’ security as a top priority, ensuring that no room exists for intruders to step in and leverage that trust for their own malintent.
HDMZ is sharing this cautionary tale because we take these security precautions seriously, and, of course, we’re nerdy enough to like these sorts of details (even if you aren’t). If you’d like a simpler explanation, or if you have questions for our web hosting team about your site’s security, drop us a line.