TIL how to hide your JS code
POSTED ON:
TAGS: obscurity javascript encryption
The post Hiding Your JavaScript Code from Prying Eyes: A Complete Guide is pretty interesting!
ONE THING TO NOTE: Encrypting a script is stronger than obfuscation, both methods are still not adequate to protect secret content. Honestly, I don't think it's worth it on a production site, and instead just go with pure server-side if you want security. But it's fascinating.
There are other, additionally creative ways, for protecting/hiding sensitive content, such as restricting access to the script file, removing the script from the DOM immediately after it has been loaded, and even hiding a script inside an image.
Tl;dr - you generate a "hidden-in-plain-sight" encrypted string, that gets download and decrypt it to a variable in your web page.
How it works #
- An HTML web page will download a remote file through an AJAX GET request.
The script itself is hidden from sight via an AJAX request. The act of the file being downloaded would only be viewable by accessing the network traffic in the browser.
-
The remote file will contain a symmetrically encrypted string, which is the actual JavaScript.
-
We decrypt the string.
Without the key, a user would not be able to access the contents. This, at least, protects the file in its target location — especially if the target location is a remote server, with no clear reference to the corresponding web page. This can be significantly stronger than obfuscation.
- Finally, we execute the decrypted script it in the web browser by using the eval() command.
The main weakness to this approach, of course, is that the secret key to decrypt the file must be located somewhere in the web page.
Storing in plain sight #
IDEA 1- hardcoded
The most straight-forward approach would be to simply hard-code the key into the web page that downloads and decrypts the file. This is simple enough to do. However, any user can view the source of the web page and access the key to decrypt the file themselves.
IDEA 2 - Compose the key from elements on the page
For example, you could select the id or class names for specific known elements in the DOM (at runtime via JavaScript) and combine these together to form a string to be used as the key.
Combining element names in the web page to form a key is essentially obfuscating the key, since a user could still follow the logic of the script to ascertain the key themselves. However, it does offer an additional layer of difficulty.
IDEA 3 - User provides a key
In this method, the user can provide the key to decrypt the file. This could be done through a login form with a POST request where the user gives the key.
IDEA 4 - Using Crypto-Js
We’re going to use the crypto-js library to perform AES symmetrical encryption. The difference between symmetrical versus asymmetrical is that asymmetrical is a one-way encryption that can not be decrypted (i.e., hash).
...We create two web pages — the first is a utility app that can be used for initially encrypting your script and saving to a separate file. The second page is for decrypting the file and loading into the target page.
<!-- ======= page-encrypt.html ====== -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
<div id="encrypted"></div>
<script>
// Encrypt Utility
// 1. Define a password.
var key = "secret";
// 2. Define an array that you want to encrypt in a separate file.
const payload = `[
'one',
'two',
'three'
]`;
// 3. Encrypt the array.
const encrypted = CryptoJS.AES.encrypt(payload, key);
// 4. Print the encrypted text to the web page.
document.getElementById('encrypted').innerHTML = encrypted;
// 5. Copy the encrytped string in the textbox, save to a new file,
// and upload to destination. This example is using github.
</script>
<!-- ======= page-decrypt.html ====== -->
<script src="https://code.jquery.com/jquery-3.6.3.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/crypto-js/4.1.1/crypto-js.min.js"></script>
<div id="decrypted"></div>
<button id="load">Load</button>
<script>
//
// Decrypt
//
// 1. Define a password.
var key = "secret";
// 2. Download the encrypted file.
$.get('https://gist.githubusercontent.com/primaryobjects/16907cd0f327119ccc5d7f2a168c5a0f/raw/4913ade697e5312c679f42c2576f8cbd07f44fd9/data.dat', data => {
// 3. Decrypt the string and evaluate back to an array named 'arr'.
arr = eval(CryptoJS.AES.decrypt(data, key).toString(CryptoJS.enc.Utf8));
});
// 4. When clicking the 'Load' button, print the contents of arr.
// This variable is now global!
$('#load').click(() => {
document.getElementById('decrypted').innerHTML = JSON.stringify(arr);
});
</script>
Related TILs
Tagged: obscurity