Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

How To Use Code Annotations When Protecting Your JavaScript

DZone's Guide to

How To Use Code Annotations When Protecting Your JavaScript

In this article, you'll find tutorial on how to use several different code annotation methods to help protect your JavaScript.

· Web Dev Zone
Free Resource

Tips, tricks and tools for creating your own data-driven app, brought to you in partnership with Qlik.

jscrambler101_lesson2_code_annotations


Introduction

Last time, in Jscrambler 101 - First Use, we talked about using our 4.0 app, applying transformations, creating templates, and learning how to export transformations as a JSON file among other tips. This time we’re going to talk about Code Annotations.

What Are Code Annotations?

Code Annotations are JavaScript comments you can add to your code. They are used to change Jscrambler’s behavior when protecting your app. Sometimes the transformations that are applied to protect your code can cause performance issues or obfuscate your code in an undesired way. Code Annotations can be used to counteract these situations.

The existing directives are:

  • enable - enables transformations and transformation aliases.
  • define - defines a transformation alias with custom options.
  • disable - disables transformations, transformation targets, and transformations aliases.
  • order - enables transformations and transformation aliases in a specific order (allows repetition).
  • target - enables all transformations available for a transformation target.

To show you how Code Annotations work, we’re going to use several code snippets, each of these will focus on a certain directive.

Enable

Starting with the getSecret function, let's assume we have a string with sensitive information such as a secret:

function getSecret() {
    return 'This is the secret.';
}

We want to encode specifically this string with sensitive information, so we add the enable directive locally.

// @jscrambler enable stringEncoding
function getSecret() {
    return 'This is the secret.';
}

This’ll enable the String Encoding transformation on our string.

function getSecret() {
    return '\u0054\u0068\u0069\u0073\u0020\u0069\u0073\u0020\u0074\u0068\u0065\u0020\u0073\u0065\u0063\u0072\u0065\u0074\u002e';
}

It still looks a bit too easy to decode, so we’re going to add String Concealing as well:

// @jscrambler enable stringEncoding, stringConcealing
function getSecret() {
    return 'This is the secret.';
}

This will become:

var uPIi = {
//string concealing and encoding
};
//...
function getSecret() {
    return uPIi.o(0);
}

Let’s say you’ve added other strings with sensitive information, and found it best to simply encode and conceal every string in the file.

function getSecret() {
    return 'This is the secret.';
}
//…

function getAnotherSecret() {
    return 'This is another secret.';
}

We can use global enable to affect the whole file, such as:

// @jscrambler global enable stringEncoding, stringConcealing
function getSecret() {
    return 'This is the secret.';
}
//…

function getAnotherSecret() {
    return 'This is another secret.';
}

This will be transformed into:

var pLZi = {
//string concealing and encoding
};
//...
function getSecret() {
    return pLZi.n(1);
}
function getAnotherSecret() {
    return pLZi.n(0);
}

Now, both of the displayed secrets have been transformed by String Concealing and String Encoding.

Disable

Imagine you’re using a file that has a global String Encoding, and you have a code block that does operations on a string.

// @jscrambler global enable stringEncoding, numberToString
var a = 'some string';
var b = 1;

//...
for (i = 0; i < 1000; i++) {
    //something happens with strings
    var s = 'disable string encoding here';
    //...
}
var t = 'should be transformed';

Say you don’t want String Encoding to transform the strings inside the loop, as it would affect the performance of the code, but you want all the other strings outside of this loop to be transformed. You can use the disable annotation.

// @jscrambler global enable stringEncoding, numberToString
var a = 'some string';
var b = 1;
//...
// @jscrambler disable stringEncoding
for (i = 0; i < 1000; i++) {
    //something happens with strings
    var s = 'disable string transformations here';
    //...
}
var t = 'should be transformed';

Now Jscrambler will act so that the strings inside the loop won’t be affected by the transformations, but everything else will be affected.

As we only have the String Encoding disabled, you’ll notice that the Number to String still worked on the for loop.

var a = '\u0073\u006f\u006d\u0065\u0020\u0073\u0074\u0072\u0069\u006e\u0067';
var b = "1" + 0;
//...
for (i = "0" * 1; i < "1000" - 0; i++) {
    var s = 'disable string transformations here';
}
var t = '\x73\x68\x6f\x75\x6c\x64\x20\x62\x65\x20\x74\x72\x61\x6e\x73\x66\x6f\x72\x6d\x65\x64';

If you don’t want any transformations at all to occur in a code block use//@jscrambler disable *

// @jscrambler global enable stringEncoding, numberToString
//...
// @jscrambler disable *
function foo() {
    var a = 'I won\'t be affected';
    function bar() {
        var b = 'I won\'t be affected either';
    }
    // @jscrambler global enable stringEncoding, numberToString
    var c = 'But I wan\'t to be affected';
    var d = 2;
}

You will notice that the strings in var a and var b aren’t affected by any transformation. We wanted var c to be affected by these transformations, though, so we had to insert a new Jscrambler enable annotation.

function foo() {
    var a = 'I won\'t be affected';
    function bar() {
        var b = 'I won\'t be affected either';
    }
  var c = '\x42\x75\x74\x20\x49\x20\x77\x61\x6e\x27\x74\x20\x74\x6f\x20\x62\x65\x20\x61\x66\x66\x65\x63\x74\x65\x64';
  var d = 2;
}

If we want var d=2; to be affected by the Number to String, though, we’ll have to add another code annotation directly above it, such as:

// @jscrambler enable stringEncoding, numberToString
var c = 'But I wan\'t to be affected';
// @jscrambler enable stringEncoding, numberToString
var d = 2;

This would become:

var c = '\x42\x75\x74\x20\x49\x20\x77\x61\x6e\x27\x74\x20\x74\x6f\x20\x62\x65\x20\x61\x66\x66\x65\x63\x74\x65\x64';
var d = "2" * 1;

Define

Define can be used for transformations that include options, such as SelfDefendingCharToTernaryOperator, and ControlFlowFlattening.

Define works by using both define and enable.

//@jscrambler define charToTernaryOperator {tern: [0,1]} as iR1
//@jscrambler enable iR1
var a = 'o';
var b = 'o';

Here we’re using the Char to Ternary Operator transformation and setting its option, tern, which is the minimum number of ternary operators between 0 and 1. This includes 0 and 1 as the minimum number of ternary operators and generates a random output.

var a = (730.08, 860.34) < 4.43 ? 0x13c4 : 'o';
var b='o';

We could use other numbers such as 2 and 3:

//@jscrambler define charToTernaryOperator {tern: [2,3]} as iR1
//@jscrambler enable iR1
var a = 'o';
var b = 'o';

This would become:

var a = (5523, 8821) < (634, 4753) ? 108.94 < (230.23, 2050) ? 2880 <= 9190 ? 610.76 : (4.35e+2, 521.21) : (false, 6.46e+2) : 'o';
var b='o';

 Define  is local and will only affect the code block below it, so remember to use global when you want to affect more than one location. For example:

//@jscrambler define charToTernaryOperator {tern: [0,1]} as iR1
//@jscrambler enable iR1
var a= 'o';
//@jscrambler enable iR1
var b= 'o';

This won’t affect var b but if we use globaliR1 can be reused in define2.

//@jscrambler global define charToTernaryOperator {tern: [0,1]} as iR1
//@jscrambler enable iR1
var a= 'o';
//@jscrambler enable iR1
var b= 'o';

The transformed code will look like:

var a = (730.08, 860.34) < 4.43 ? 0x13c4 : 'o';
var b = (273.32, 907.6) === (1500, 5782) ? (9.92e+2, false) : 'o';

Aliases, as all other code annotations, are inherited from upper blocks. So if you define an alias for a block you can enable it not only in that block but also in any of the inner statements and blocks without using global.

// @jscrambler define charToTernaryOperator {tern: [0,1]} as iR1
function foo() {
 function bar() {
   // @jscrambler enable iR1
   function baz() {}
 }
}

In this case, only baz() will be affected by the charToTernaryOperator.

Order

 Order allows transformations to be executed in a set order. As an example:

// @jscrambler order numberToString, stringEncoding
var strNum= 123;
// @jscrambler order stringEncoding, numberToString
var numStr= 456;

The strNum variable will first be affected by numberToString, followed by stringEncoding, while numStr will first be affected by stringEncoding, then numberToString
You’ll notice that numStr was only affected by numberToString, since at the time stringEncoding was performed, there wasn’t any string to act on.

var strNum = +'\x31\x32\x33';
var numStr = "456" | 0;

 Order is best used to handle situations such as these where the order in which the transformations are applied severely affects the outcome. Imagine you want to set a specific order for the whole JavaScript source code. To do this you can use the global modifier.

// @jscrambler global order numberToString, stringEncoding
var strNum = 123;
var numStr = 456;

This will become:

    var strNum = +'\u0031\u0032\u0033';
    var numStr = '\u0034\u0035\u0036' - 0;

You can also repeat transformations, but the number of times you can repeat the same transformation is limited to 3 times. Something like:

// @jscrambler order dotToBracketNotation, numberToString, stringEncoding, numberToString, stringEncoding
map.moveTo(0, 0);

Is transformed to:

map['\u006d\u006f\u0076\u0065\u0054\u006f'](+'\u0030', '\u0030' - +'\u0030');

By repeating numberToString and stringEncoding, the numeric arguments produced by the first stringEncoding were transformed and all strings were encoded twice.

There are some transformations that can only be used once per node. These are:

The order can also be inherited so if you define a specific order for a block, any inner statement and block will inherit it and combine it with any directive defined at that point. This means that:

// @jscrambler order A, B, C
function foo() {
 // @jscrambler order D, E
 function bar() {}
}

Will be applied in the following order:

// [A, B, C]
function foo() {
 // [D, E, A, B, C]
 function bar() {}
}

Code annotations prioritize local order so D and E will alway be performed before A, B, and C. 
Transformations are also merged if they are repeated such as:

// @jscrambler order A, B, C
function foo() {
 // @jscrambler order A, A
 function baz() {}
 // @jscrambler order B
 function qux() {}
}

Will be merged to act the in the following manner:

// [A, B, C]
function foo() {
 // [A, A, B, C]
 function baz() {}
 // [B, A, C]
 function qux() {}
}

For the baz function, transformation A is executed twice as it was defined locally that way. 
For the qux function, B is executed before A and C, because the local code annotation has priority over the global annotations, and the global B end up being merged with the local B.

Target

Now, say you have the following function:

function foo() {
    var reallySuperMegaHugeBigLongVar = 'target me!!';
}

You know you want to target the strings and identifiers in the function, but aren’t sure what transformations you should apply. 
If you were to add a target strings, identifiers as we did below:

//@jscrambler target strings, identifiers
function foo() {
    var reallySuperMegaHugeBigLongVar = 'target me!!';
}

And then run a protection, you’ll notice that both the string and identifiers are affected. This is because Jscrambler will target strings and identifiers, applying transformations accordingly.

var aWua = {
//string transformations
};
//...
function foo() {
    var i = aWua["f"](0);
}

The available targets are:

  • booleans
  • controlFlow
  • functions
  • identifiers
  • numbers
  • objects
  • predicates
  • regularExpressions
  • statements
  • strings
  • variables

Target is equivalent to a global enable of a set of transformations so it will affect all functions in a file. It’s easy to use especially if you don’t know what transformations are available, but know what you want to protect.

You can test all these Code Annotations at https://app.jscrambler.com/. Simply create a new app, insert the code snippets, and run a protection without selecting any transformations.

You’ll see that the resulting code has the protections applied according to the used code annotations. Since we didn’t apply powerful sets of transformations, you can easily see how each code annotation affected each snippet.

Conclusion

This concludes our second tutorial on how to use Jscrambler. You should now be able to easily use Code Annotations to change Jscrambler’s behavior when protecting specific code blocks. Remember to check our Documentation for further information and examples on our transformations, code annotations, and API. Don’t forget to use the global modifier, when you want to affect the whole source file.

On our next tutorial, we'll demonstrate how our Self-Defending works, and how you can use it to avoid users from debugging and tampering your code.

Enjoy your testing and start protecting your Applications ASAP!

Explore data-driven apps with less coding and query writing, brought to you in partnership with Qlik.

Topics:
javascript ,web security ,web dev

Published at DZone with permission of Pedro Fortuna. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}