Protecting multiple files
JSDefender handles scenarios when you use multiple JavaScript files in an application.
If you use multiple files, often, you cannot protect them separately, as there might be correlation among them. JSDefender applies its protection on multiple files correctly, if you specify their load order properly.
Specifying multiple files
To protect multiple files, you need to specify them in the inputs
section of the configuration file in the same order as they are loaded in the web page. So, let's assume you work with the two files used in the previous example:
file1.js
:
function getGreeting() {
var name = getName();
return "Hello, " + name + ", from multifile demo!";
}
file2.js
:
function getName() {
return "Developer";
}
var element = document.getElementById("msg");
element.textContent = getGreeting();
Now, use this configuration file (it assumes that file1.js
and file2.js
are in the current working folder, just as jsdefender.config.json
):
jsdefender.config.json
:
{
"inputs": ["file1.js", "file2.js"],
"settings": {
"localDeclarations": {
"nameMangling": "sequential"
},
"stringLiterals": false
}
}
After running the jsdefender
command line, these are the protected output files:
file1.js
:
function _0x000000() {
var _0x000001 = _0x000002(); // ID declared in file2.js
return "Hello, " + _0x000001 + ", from multifile demo!";
}
file2.js
:
function _0x000002() {
// file1.js has a reference to this ID
return "Developer";
}
var _0x000003 = document.getElementById("msg");
_0x000003.textContent = _0x000000();
Look at the _0x000002
identifier, the renamed version of getName
in the original code. It was correctly replaced in both protected files.
Why the Order of Files May Matter
As you learned at the beginning of this document, JSDefender expects that you specify multiple files in their loading order. This section explains the reasons for that.
Issues with Multiple Files Loaded in a Single Page
Let's look at a short example where the separate protection of two files loaded in the same web page may break working code.
Local declaration renaming (name mangling) is an excellent protection option, as it changes meaningful identifiers to a meaningless string of letters and digits. However, when you have multiple files, using JSDefender separately on those files may break the code, as the following example demonstrates.
Assume, you have two files, file1.js
, and file2.js
. The browser loads these files into an HTML page in this order:
...
<script src="file1.js"></script>
<script src="file2.js"></script>
...
file1.js
:
function getGreeting() {
return "Hello from multifile demo!";
}
file2.js
:
var element = document.getElementById("msg");
element.textContent = getGreeting();
You can protect these two files by running the JSDefender CLI twice, once for each file. As a result, you get these files after local declaration renaming:
file1.js
(protected):
function _0x000000() {
return "Hello from multifile demo!";
}
file2.js
(protected):
var _0x000000 = document.getElementById("msg");
_0x000000.textContent = getGreeting();
There are two issues:
- Each module contains a declaration,
_0x000000
. Because of the JavaScript declaration hoisting mechanism, the second_0x000000
declaration (infile2.js
) overwrites the first one. - As
getGreeting
is not a local declaration infile2.js
(it is just an identifier reference), it is not renamed.
This code will break when the browser loads the page.
Take a look at the next scenario that again uses two JavaScript files:
file1.js
:
function getGreeting() {
var name = getName();
return "Hello, " + name + ", from multifile demo!";
}
file2.js
:
function getName() {
return "Developer";
}
var element = document.getElementById("msg");
element.textContent = getGreeting();
After invoking JSDefender for each file separately, this is what you get:
file1.js
(protected):
function _0x000000() {
var _0x000001 = getName();
return "Hello, " + _0x000001 + ", from multifile demo!";
}
file2.js
(protected):
function _0x000000_() {
return "Developer";
}
var _0x000001 = document.getElementById("msg");
_0x000001.textContent = getGreeting();
You can immediately see that this code breaks, too:
- Each file contains a declaration,
_0x000000
. Because of JavaScript declaration hoisting, the declaration infile2.js
overwrites the first one. - As
getName
is not a local declaration infile1.js
(it is just an identifier reference), it is not renamed. - As
getGreeting
is not a local declaration infile2.js
(it is just an identifier reference), it is not renamed.
So, please make sure that you take care of file order when using JSDefender with multiple files.