Protecting javascript from copying


14-08-2018
Денис Л.
Javascript
Protecting javascript from copying

Not so long ago I developed a calculator for calculating the cost for a company in which I work, with a large number of interrelated parameters. Everything is done with javascript. The management set a task to protect the script from copying, so that competitors could not use it on their websites. I was looking for various solutions, I did not find anything suitable, so I started writing my own solution. I present it below.

I draw your attention that any code can be decrypted, it just takes time. Therefore, this decision, of course, is not ideal. Nevertheless, in order to uncover it, it takes time, attention and perseverance. And this can alienate your competitors from the idea of copying your script. Most of them after several unsuccessful attempts will simply look for an analogue of a similar script on other resources.

By the results of the work in the browser you will see this:

<script>glob('KKGZ1bmN0aW9uKCQpIHsNCgkkKGRvY3VtZW50KS5yZWFkeSggZnVuY3Rpb24gKCkgew0KDQoJCWlmKCAkKCdkaXYnKS5pcygnLmNhbGMnKSApIHsNCg0KCQkJJCgnLmNhbGMgPiAucm93JykuZWFjaChmdW5jdGlvbihpKSB7DQoJCQkJJCh0aGlzKS5hdHRyKCdkYXRhLXN0ZXAnLCBpKzEpOw0KCQkJfSk7DQoNCgkJCSQoJy5jYWxjID4gW2Rhdgetc3RlcD0iMSJdJykuYWRkQ2xhc3MoJ2FjdGl2ZScpOw0KDQoJCQkkKCdhW2hyZWY9Ii9zdG9pbW9zdC8iXScpLmNsaWNrKGZ1bmN0aW9uKGUpIHsNCgkJCQllLnByZXZlbnREZWZhdWx0KCk7DQoJCQkJJCgnLmNhbGMnKS5mYWRlVG9nZ2xlKCk7DQoJCQkJeWFDb3VudGVyMTM4ODc0NTcucmVhY2hHb2FsKCdjYWxjX29wZW4nKTsNCgkJCX0pOw0KDQoJCQlpZiAoICQodzZW5kJyk7DQoJCQkJCQl5YUNvdW50ZXIxMzg4NzQ1Ny5yZWFjaEdvYWwoJ2NhbGNfc2VuZCcpOw0KCQkJCQl9DQoJCQkJfSk7DQoJCQkJc2V0VGltZW91dChmdW5jdGlvbigpIHsNCgkJCQkJJCgnLmNhbGMnKS5mYWRlT3V0KDc3Nyk7DQoJCQkJCSQoJ2EuYnV0dG9uc0ZvckRvY3MnKS5jc3MoJ21hcmdpbi10b3AnLCAnMTVweCcpOw0KCQkJCX0sNzAwMCk7DQoJCQl9KTsNCg0KCQkJJCgnI3RoYW5rc0J1dHRvbicpLm9uKCdjbGljaycsIGZ1bmN0aW9uKCkgew0KCQkJCSQoJy5jYWxjJykuZmFkZU91dCgxMDApOw0KCQkJCSQoJ2EuYnV0dG9uc0ZvckRvY3MnKS5jc3MoJ21hcmdpbi10b3AnLCAnMTVweCcpOw0KCQkJCWNhbGNSZWJvb3QoKTsNCgkJCX0pOw0KDQoJCQkkKCcuY2FsYyAuY2xvc2UnKS5vbignY2xpY2snLCBmdW5jdGlvbigpIHsNCgkJCQkkKCcuY2FsYycpLnJlbW92ZSgpOw0KCQkJCSQoJ2EuYnV0dG9uc0ZvckRvY3MnKS5jc3MoJ21hcmdpbi10b3AnLCAnMTVweCcpOw0KCQkJfSk7DQoNCgkJfTsNCg0KCX0pOw0KfSkoalF1ZXJ5KTs=')</script>

In this case, all encrypted scripts will work correctly. Visually, an experienced view of the programmer will immediately determine the coding via base64. But when you try to decode a string with any base64 decoder, will be an error... If you insert a script in alert (This method is also recommended on forums for code decryption), then the result will also be incorrect.

In this case, because no one knows that it is here that the script is encrypted. After all, it can be some kind of parameter, either text or image. Through base64 you can encrypt anything, anything. This will confuse fans to press 'ctrl C' add 'ctrl V'.

Let's look in the code for the function glob, to which the encrypted string is sent.

Here she is: glob=function(s){sfd(rty(s.substring(1)));

We see several more functions sfd и rty. Looking for these functions.

Here they are: sfd=this["\x65\x76\x61\x6C"];rty=this["\x61\x74\x6F\x62"];

At this point, many will end up decrypting and leaving your site alone.

And we will discuss everything in more detail.

So, how to protect javascript from copying on your site

First of all, we specify in the footer of the site the path to our script and immediately encode it:


  <?$filebase64='K'.base64_encode(file_get_contents('/home/bitrix/www/js/script.js'));?>

In the line above we tell the php interpreter to take a file script.js, then encode it using base64, then add a row 'K' and write all this into a variable $filebase64

Why did we add a letter 'K'? (this, by the way, can be any Latin letter or a combination of letters or numbers) This protects us from the fact that anyone who wants to copy your script will decrypt it using alert or online decoder. After all, with additional symbols, the script will not work.

Then a little further in the code call the script:


  <script>glob('<?=$filebase64?>')</script>

Let this script be called separately, away from other scripts and links to scripts.

Then somewhere in the file with the general scripts of the site, separately from other scripts, we insert the call of the decryption functions. You can insert independently of other functions and libraries.


  sfd=this["\x65\x76\x61\x6C"];rty=this["\x61\x74\x6F\x62"];glob=function(s){sfd(rty(s.substring(1)));}

We disassemble in detail what is happening here.

Our main function glob takes one parameter 's'. The parameter 's' is immediately passed to the function substring with parameter '1', which takes a string in the parameter 's', starting with the first character (which is specified in the parameter) and to the end of the line. Therefore, if we added more than one symbol in the php code, for example 3, then we need to be in function substring indicate the figure 3.

Further, the obtained result is taken by the function rty(). This function is a set of characters, namely: this["\x61\x74\x6F\x62"];

Try typing this in the browser console and you'll see what this function actually does. You will see:


  ƒ atob() { [native code] }

Ie, a character set is an encrypted function atob, which makes Decode a base-64 encoded string, decodes a string derived from base-64.

The resulting decoding result is processed by the function sfd(). It is also a character set: this["\x65\x76\x61\x6C"];

Have you guessed what to do? :) Execute in the browser console and you will see:


  ƒ eval() { [native code] }

Here, I think, there is nothing to explain. We all know that the function eval executes the script obtained from the string. "Bad practice", as many would say, but in our case this is a safe and necessary function for us to implement our idea. In addition, directly to this function, the user will not be able to access.

Probably, you asked a question, but how are the functions encrypted in a set of characters? Very simply: a character set is text converted to a hexadecimal number system. Those. it's text, in format Hex (hexadecimal). Through hex, you can encrypt any characters.

Thus, our decrypted function looks like this:


  glob = function(s) {
    eval(
      atob(
        s.substring(1)
      )
    );
  }

Specially divided into lines, so that it was visually.

As a result, we discard the first character of the encrypted string, then decrypt it, then perform it with eval.


You can go further. If somehow someone decrypts your script, complicate it slightly, so that people find it more difficult to modify it. For example, in the code we often compare something with numbers '0', '1', '-1'.

You can replace these numbers with:

-1 can be replaced by: ~[]

1 can be replaced by: -~[]

0 can be replaced by: ~~[]

Similarly, you can replace the values 'true' и 'false': 'true' is similar to 1 for a non-strict comparison, and 'false' is similar to 0, also for a non-strict comparison.

Everything will work as before, but will confuse bad people :)


Still, of course, you can talk about a bitwise operator ^, with which you can work miracles... For example, a^b^b will be equal to a. As a b a key can be used, which we encrypt somewhere above. But I'll tell you about this somehow in other posts...