JavaScript obfuscator: protection for your own code

You want to protect your JavaScript code with the valuable algorithms against attackers? JavaScript obfuscator has some tools – from a few minimization tools to complete server-based solutions – that make it difficult for the attacker to survive. Often it is sufficient if the attacker decides after a brief glance that he prefers to clone another application.

The field of JavaScript obfuscation is wide: it ranges from simple minimization tools to complete server-based solutions. In this article, I’d like to conceptualise a few ways to learn more about the different approaches. It should be noted at this point that obfuscators are not a substitute for server-side verification. A technique known as fuzzing allows attacks against extremely complicated protocols – the advice to treat information received from the client as toxic also applies when using all the methods discussed in this article.

With brute force!

As so often in the world of computer science, here too there is no universally safe solution. The task of all discussed procedures is to make an attack so expensive that it is not worthwhile for hackers. If one is dealing with extremely sensitive or questionable intellectual property, the use of obfuscators is often insufficient. In this case, it is recommended to rely on a client-server architecture.

This strange at first glance approach is easily implemented in times of WebSocket and Co. Surprisingly, users complain in practice only a little if their program does not work without network connection. The author tested this under Firefox OS: Despite permanent connection to the server, the in-house scientific calculator received the best ratings. A similar notion is the use of a product such as emscripts. The framework developed by Alon Zakai allows the compilation of C code, which then runs in a virtual machine.

Although the code is on the client’s machine, it is extremely difficult to analyze. Encrypted code is similar in complexity to Qt and Co. Complaints about disassembler attacks on C ++ programs are very rare, unlike in the world of Java or .NET.

A question of the concept!

If you do not want to rely on brachial methods, there are a variety of obfuscators available. By and large they behave the way you know it from the Java world. On the left is readable code in the black box, which played on the other side alienated code. Ideally, the cipher can be executed immediately. That the practice looks different, is already noted here.

When working with JavaScript Obfuscators a special feature has to be considered. While Obfuscators for other programming languages ​​usually help to speed up the program by reducing the size of the program, JavaScript conspirators often have a negative impact on overall performance. The cause of this paradoxical behavior lies in two things: firstly, the spoiled code is often more extensive than the basic variant, which slows down the execution. This is unavoidable, as the introduction of arrays, global jump tables and similar niceties naturally cost computing power.

A second, and even more annoying, antipattern is the mess of third-party libraries. By way of explanation: If you use a common version of jQuery, the browser can get it from a CDN (or even from its local cache) and speed it up in several ways. Instead, a variant of the library encrypted by you would have to be completely read in and parsed, which consumes valuable time.

The JavaScript developed by Timofey Kachalov Obfuscator is a classic of the scene. It differs from competitors like UglifyJS in that it is not just limited to removing control characters and other pleasantries, but also interferes with the code structure to make it difficult to use JavaScript beautification programs. If desired, the Obfuscator even integrates check routines that automatically disable the code upon detection of the format change.

Even if an online version of the tool is available at https://obfuscator.io , the use of a local installation is recommended for serious attempts. This requires Node.js, the author’s workstation had version 10.1.0 installed. NPM is responsible for the download and was available under Ubuntu 14.04 in the form of the externally downloaded version 5.6.0.

JavaScript Obfuscator can be installed in several ways. Those who do not work with a project that lives in Node.js should install the program globally for the sake of convenience. The following command sequence is used for this (if authorization errors occur, you must place sudo before the call):

[email protected]:~$ npm install -g javascript-obfuscator
. . .
+ [email protected]
added 103 packages in 8.074s

After passing through the command, check the successful installation by entering the command javascript-obfuscator in your terminal.

To demonstrate the obfuscation services, we want to implement a small sample program in the next step. His body presents itself as seen in Listing 1.

var myString = "Hello"

function doTheTrick(){
var chiffrat;
chiffrat = rot13(myString);
return chiffrat;
}

function rot13(str) {
var re = new RegExp("[a-z]", "i");
var min = 'A'.charCodeAt(0);
var max = 'Z'.charCodeAt(0);
var factor = 13;
var result = "";
str = str.toUpperCase();

for (var i=0; i<str.length; i++) {
result += (re.test(str[i]) ?
String.fromCharCode((str.charCodeAt(i) - min + factor) % (max-min+1) + min) : str[i]);
}
return result;
}

In this example program, which looks primitive at the first step, there are two malignancies. First, we have a method called rot13 that implements a – admittedly somewhat primitive – form of encryption. The implementation adopted by rot13 is based on talking variable names , which greatly facilitates an attacker’s analysis.

At least as hot is the use of the string constant. This is a classic attack vector: One of the first approaches to analyzing a ROM dump is to animate the disassembler to search for strings.

Practical experience teaches that JavaScript obfuscators with HTML code are in desperate need. For this reason, we include the .js file in a second harness, which in turn also has a method (Listing 2).

< html >
< body >
< script src="worker.js" >< / script >
< script >
function worker(){
alert(doTheTrick());
}
< / script >
< button type="button" onclick="worker()" >Click Me!< / button >
< / body >
< / html >

Then run the program to make sure that the MessageBox appears correctly. The author purposely does not rely on complex DOM manipulations, so as not to unnecessarily inflate the code of our example.

At this point we can dare a first attempt towards obfuscation:

[email protected]:~/SUSObfuscate$ javascript-obfuscator . --output ./subfolder

[javascript-obfuscator-cli] Obfuscating file: worker.js...
(node:20534) ExperimentalWarning: The fs.promises API is experimental

We currently only pass the minimum rate. He directs the product to search for JavaScript files in the current working directory. With the parameter output we instruct a “redirection” of the encrypted files. If this parameter were omitted, we would find an additional colleague with an extended name instead of worker.js .

The choice of the best course of action is by and large a matter of taste. The author prefers the diversion presented here to a new directory. A “working” version of the application can be created by copying the. Html and other files into the subfolder subfolder .

If you execute the encrypted version of the program, you see that the red13-modified string is still displayed in a dialog. It is much more interesting to open the code in the new version of worker .

If you encrypt the code with the default settings of the program, you see that the structure has been complicated by enrolling methods. Unfortunately, the keys are still clearly visible. In addition to the toUpperCas e field, for example, we find the functions rot13 and doTheTrick.

The string in the center

The experiments just made have greatly reduced the clarity of our code. Unfortunately it is still easy to guess the “task” of the program. Providers of obfuscators have always suffered from the fact that they have to balance several aspects in the parameterization. In addition to the difficult legibility, it is important to pay attention to performance and stability. In practice there are always situations in which a program can no longer be carried out after the opposition.

The JavaScript Obfuscator provides three parameters for configuring string processing:

--string-array < boolean >
--string-array-encoding < boolean|string > [true, false, base64, rc4]
--string-array-threshold < number >

To understand the behavior of the program we want to refer to http://jsnice.org – an analysis service, the dirty JavaScript code, as shown in pic 4 , cleanly.

jsnice-org

In-depth strings

The inherently disabled value string-array-encoding determines how the strings to be dropped in this array are rooted. If it is set to True , the coding is done with Base64. If you use RC4 instead, the string will be even more distorted. Unfortunately, the procurement of the values ​​is then between 30 and 50 percent slower. Finally, there is the value string-array-threshold , which affects the paging probability of strings. Our obfuscator does not inherently store all the strings. The program instead executes a random number generator to transpose only some strings. The purpose of this task is to perform the performance-intensive calls of the array as little as possible.

It should be noted that code working with sensitive string constants must necessarily set the value to one. Practical experience teaches that once a key has been obtained, it can no longer be captured. When a hacker abuses various cloud services at their expense, they learn to curse in multiple languages. Fortunately, improving the security of the string requires only a – comparatively minimal – adjustment of the parameterization:

[email protected]:~/SUSObfuscate$ javascript-obfuscator . --output ./subfolder --string-array-encoding base64
[javascript-obfuscator-cli] Obfuscating file: subfolder/worker.js...
[javascript-obfuscator-cli] Obfuscating file: worker.js...

If you look closely at the output of the obfuscator, you will notice that it is editing the already alienated file again. This is because passing in a directory name as an input basically animates the obfuscator to manipulate the directory and all its subfolders equally.

Therefore, make sure to delete the directory in which the already edited files are located before calling the obfuscator. This can be done in a build system, for example, via a command line command, which is fired before the actual execution of the compilation process.

At least the string looks a lot less clear after the work is done:

var a0_0x4370=['dGVzdA==','ZnJvbUNoYXJDb2Rl',. . .

Note that the now encrypted existing strings must be provided before use. This task takes time, which interferes especially with performance-critical code.

It should be noted that no matter how well he works, an obfuscator can never provide 100% certainty for constants. Keep in mind that the code must be executed in the browser of the client. The sensitive information must therefore at some point be available as decoded plain text. An attacker can – assuming sufficient motivation – this tap if necessary in the transfer to API and Co.

Advanced malignancy

So far, JavaScript obfuscator has been limited to complicating the structure of the present code. However, the program is also capable of implementing security routines that make it difficult for debuggers to execute the code. There are also features that make the execution on foreign domains impossible.
As a first attempt, we try to limit the code to a domain. In theory, it would be sufficient to pass a domainLock parameter to the obfuscator:

[email protected]:~/SUSObfuscate$ javascript-obfuscator . . . --domainLock www.helpdev.eu

At this point, there is an interesting trend: The providers of browsers and other systems are trying to set killer code active out of action. The parameter was equally ineffective in tests of the author under Chrome and Firefox. This cat-and-mouse game is well known by embedded compilers. Do not assume that an offensive feature will still work as expected six months after delivery by the Obfuscator provider. Unfortunately, that works in practice – especially with very simple code – rather bad than right. In tests of the author, the message appeared even if the transferred domain was incorrect.

Another offensive tool is the debugProtection . The idea behind this is that JavaScript obfuscator inserts code into the program, which in one way or another puts the debugger out of action. To use this function, it is sufficient to set the value to true during the run:

[email protected]:~/SUSObfuscate$ javascript-obfuscator . . . --debugProtection true

Here, too, the trend discussed above shows: In all installed on the workstations of the author’s browsers, although activated option to higher CPU resource consumption, the developer tools remained – on the whole – but functional.

Last but not least, I would like to introduce you to two option groups that make more profound changes to the source code:

--control-flow-flattening < boolean >
--control-flow-flattening-threshold < number >
--dead-code-injection < boolean >
--dead-code-injection-threshold < number >

When dead-code injection is enabled , the obfuscator inserts dead code into the output routines. The idea behind this is that the embellished program will still be extremely long, making it difficult to analyze the control flow. On the downside is the naturally slower execution of the code.

Behind control-flow-flattening hides an option known as inlining from the field of microcontroller technology. The Obfuscator replaces function calls with the code of the method in this case. The reward of the effort is much greater scope of programs, but it is harder to analyze by hand. In both cases, the program uses random number generators to trigger the activation of the respective feature. The higher the value of the respective threshold, the more likely the appearance of the respective structure. It should be noted that the JavaScript Obfuscator can not only be activated from the command line. The development team also provides plug-ins for various packaging systems.

At the time of printing there are extensions for webpack , Gulp and Grunt . All three work analogously in principle – in the case of webpack, for example, you must enter the following npm command for installation:

npm install --save-dev webpack-obfuscator

In the next step you can call the JavaScript Obfuscator directly from webpack. This requires small adjustments in the configuration file. In addition to loading the plug-in with require , we write the resulting object into the plugins array:

var JavaScriptObfuscator = require('webpack-obfuscator');

// webpack plugins array
plugins: [
new JavaScriptObfuscator ({
rotateUnicodeArray: true
}, ['excluded_bundle_name.js'])
],

In practice, it is highly advisable to resort to such services. It’s only a matter of time before a developer forgets to do manual obfuscation in the rush. As in the case of the above-mentioned key, it is then also the case here that one can not recover the code once it has been recovered.

And now in commercial

The team around Timofey Kachalov is quite respectable in terms of support – Issues are answered quickly, even stupid questions get a friendly response. Especially in very sensitive situations you sometimes want a completely commercial company. In this area, Jscrambler has emerged as a classic. The product was recommended by Gartner in various publications.

It should be noted at this point that the jscrambler team does not publish price information on its website. Anglo-Saxon sources cite starting prices of $ 85 a month for undefined startups. The use of this product is certainly not an offer for small developers.

In exchange Jscrambler promises extensive code protection. The analysis does not stop after the compilation, but is also continued in the client’s browser. The company promises to detect and ward off manipulation of the DOM. This helps, for example, if the attacker gets on the program with a debugger.

If you want to try the software, you can sign up for a mail account at https://jscrambler.com/signup .

The software here differs from JavaScript Obfuscator in that they have to create a new project on the server. To do this, you can click on the Dashboard button. The created by the developer of house Playground is just an example folder, via the button Create App you can always add your own application.

The next step is to upload the information and files on your workstation. Note that the demo version only allows a maximum of 25 files per project. In the interest of convenience, we want to recycle our example project just created here. Note that some advanced protection options are only available within the playground.

After uploading the two files, you will find the Applications Modes section on the right side of the screen. The program inherently offers a set of templates that automatically enable commonly used or appropriate protection features for specific usage scenarios. We want to click the Web Browser App option in the following steps so that it is marked with a green tick.

In the next step we can switch to the Templates section. It presents itself as shown in pic. Note that each option will bring a group of subparameters to the screen by clicking.

obfuscation

Especially fun in this context is the function OS Lock , which enriches the code with elements that bring certain JavaScript Runtimes out of step. At the time of going to print, you can target the following operating systems:

  • Linux
  • Windows
  • MacOS
  • Tizen
  • Android
  • iOS

After fully configuring the protection options to apply to the code file, you will find the Save Template button on the bottom of the screen. There you can assign a name, under which the parameter collection can later be addressed in the user interface. After work, you can click on the Protect App button to start the actual process.

Conclusion

When Microsoft released .NET, there was a similar hysteria in the marketplace: developers assumed they were losing their intellectual property. In practice, the situation proved less critical. In the world of JavaScript, the situation is likely to be somewhat similar. Anyone who worries about valuable algorithms will find tools that make the attacker’s life difficult with the various obfuscators. As is often the case here, the Saint Florian principle applies: your code does not have to be completely invulnerable. It is sufficient if the attacker decides after a brief glance that he prefers to clone another application. In this sense: have fun!

Recent Articles

Angular 9 Next Versions: Ivy, Bazel and more

Angular 9 next versions are here. Besides updates to Ivy, the update includes three features for the Language Service and Service Worker and changes...

Google Releases Dart 2.5: Code Completion through Machine Learning

The latest version of Googles C-Alternative, Go 1.13, is barely released, as the JavaScript derivative of the Internet giant follows: Dart 2.5 is here!...

Laravel 6.0 is here: Support for Serverless Platform Laravel Vapor

A new update is available for the framework Laravel. Laravel 6.0 is compatible with Laravel Vapor, a serverless deployment platform. The development team has...

Microsoft’s FaaS service Azure Functions: Now with Python support

Azure Functions has received support for Python: Microsoft's FaaS service can host Python workloads for data science, machine learning, and more. So far, the...

On the way to Angular 9: Three bugfixes in Angular 9

With Angular 9.0.0-next.1 there is a second Next-Release available for Angular 9, which can now be tested. The number of changes to the version...

Related Stories

Leave A Reply

Please enter your comment!
Please enter your name here