Javascript Copy Protection

Contents

Introduction

I have made DHTML Chuckie Egg available for educational purposes and have no intention of hiding the source code from prying eyes. However, Javascript copy protection is an interesting subject and knowledge in this area could be useful for someone writing their own DHTML based game or Javascript application.

Deterring pirates

You can never truly protect your Javascript code. Ultimately your web browser will give the Javascript to an interpreter which demands it to be in a decoded/un-protected form. Hypothetically even if it was protected at this stage, someone armed with a debugger or the source code to the javavscript interpretor could hook in and steal your hard work.

The best we can hope for is to deter pirates by making the Javascript code very difficult to understand. Code obfuscation makes it more difficult (but not impossible) to steal your program.

Obfuscation

There are lots of tools available on the web for obfuscating your code. This usually involves stripping all comments, removing white space / new lines and replacing variable names with meaningless symbols. Some obfuscators also use escape sequences to make text strings and numeric values harder to read.

escape()/unescape() functions

Another technique which can be combined with obfuscation is to use the in-built Javascript escape() function. This essentially takes your program as a Javascript string and turns it into a sequence of escaped codes. This renders the program unreadable unless unescape() is used to reverse the effect. Usually, the escaped string is embedded in your HTML/Javascript and after being unescaped() it is passed to the eval() function to be evaluated.

Hiding obfuscated code

Ordinary Javascript embedded in a .js or HTML file can easily be retrieved from the cache or viewed by right clicking in your web browser and choosing 'View Source'. A debugger plug-in will even let you step through the Javascript and inspect values on the fly. If the code is obfuscated, it is still readily available and un-obfuscatable. However, if your code is stored in a string and passed to the eval() function, it doesn't have to be embedded in your source files. Representing your Javascript as a string makes it impossible to step through in a debugger too.

Requesting code using AJAX

Rather than embedding your Javascript program in a HTML or .js file, it is possible to retrieve it from the server using an AJAX request. This can safely be invoked from the page's onload() call-back and the resulting response string could simply be passed to eval() thus avoiding having to embed the code in your source files. As an extra level of protection, it is prudent to disable caching of the AJAX data.

setRequestHeader('Cache-Control', 'no-cache');
is not reliable in all browsers. An alternative is to randomise the AJAX URL using the current time in milliseconds e.g.
'http://www.myserver.com/get.php?sid=' + new Date().getTime();

Session cookies

To bolster security further, it is possible to use a cookie generated by the server when the original HTML page was requested to validate the authenticity of the client making the subsequent AJAX request. The server would simply not honour the AJAX request if the cookie sent in the AJAX request was not valid. The main benefit of this technique is that it prevents someone from copying your code verbatim and hosting it on their own web site - this is because cookies are specific to a domain name. They would have to crack the obfuscation first and remove the session cookie protection/validation. If the cookie is very short lived, (in the order of seconds) it narrows the window of opportunity for someone trying to steal your code by using a debugger or looking in a cache etc. Using eval() multiple times to peel away each layer of obfuscation coupled with multiple AJAX requests and cookies with short life spans makes for an effective deterrent.

Compression and decompression

Another obfuscation technique is to compress your Javascript program using something like LZW (see my Javascript LZW implementation). This can be coupled with standard obfuscation, escape()/unescape(), uuencode or an encryption algorithm such as BlowFish. The client side javavscript would need to decompress the result and present it to eval() as a string. Compression algorithms output binary data so before sending it to the client, the data needs to be transformed into a text string using either uuencode, yEnc or base64 encoding. This is because AJAX only reliably handles XML or text data transfer. uuencoding adds approximately a 30% overhead to the size of your data.

Proposed strategy

If your main goals are to prevent other websites hosting your game without consent and you want to make it hard for people to steal your code or modify it , then the following strategy may help.