Search code examples
javascriptjsonnode.jssecurityswig-template

Protecting raw JSON data from being copied


I'm creating an application with Node.js and Mongo DB, rendering the views with Swig. I have a database of business names, addresses and geo location data that is being plotted onto a Google map with pins.

I'd like to stop users from easily copying the raw JSON data using view source, Firebug, Chrome Dev tools etc.

I'm not after bank grade security, just want to make it hard enough for most users to give up.

I have two routes of delivering the JSON package to the browser:

1) Using Swig, passing the JSON package directly to the view. Problem is that a simple view source will show the JSON.

2) Requesting the data with an AJAX call. In this scenario the data is easily accessible with Chrome Dev tools.

What are my options?


Solution

  • Base-64 encode the string.
    Then you can just base64-decode it in JavaScript.
    That should make it sufficiently unreadable, no real security though - of course.
    Plus it's fast.

    You need to take care with UTF-8 characters (e.g. German äöüÄÖÜ, or French èéàâôû)

    e.g. like this in JavaScript:

    var str = "äöüÄÖÜçéèñ";
    var b64 = window.btoa(unescape(encodeURIComponent(str)))
    console.log(b64);
    
    var str2 = decodeURIComponent(escape(window.atob(b64)));
    console.log(str2);
    

    example:

     var imgsrc = 'data:image/svg+xml;base64,' + btoa(unescape(encodeURIComponent(markup)));
     var img = new Image(1, 1); // width, height values are optional params 
     img.src = imgsrc;
    

    More secure variant:
    Return encrypted base64 encoded JSON, plus the decryption algorithm, base64 encode them server-side, bit-shift it a few bits, return via ajax, then de-bitshift the string on the webpage, pass it to eval, which will give you the decrypt function, then decrypt the encrypted base64 string, then base-64 decode that string.

    But that takes only a few seconds more on the chrome debug console to decrypt, i did decrypt such a thing once, I think on codecanyon to get to a "Tabs" script for free; (don't bother for the tabs, they're bloatware, better invest the time to do it yourself) ;)

    I think you find that nowadays here http://www.slidetabs.com/, but I don't know if the "encryption" method is still in there.

    Additionally, you can also escape the string in JavaScript, that then looks like this:

    var _0xe91d=["\x28\x35\x28\x24\x29\x7B\x24\x2E\x32\x77\x2E
    
    ...
    
    
    x5F\x63\x6F\x6E\x74\x5F\x64\x75\x72\x7C\x76\x5F\x74\x61\x62\x73\x5F\x61\x6C\x69\x67\x6E\x7C\x76\x5F\x74\x61\x62\x73\x5F\x64\x75\x72\x7C\x76\x5F\x73\x63\x72\x6F\x6C\x6C\x7C\x63\x6F\x6E\x74\x5F\x61\x6E\x69\x6D\x7C\x63\x6F\x6E\x74\x5F\x66\x78\x7C\x74\x61\x62\x5F\x66\x78\x7C\x72\x65\x70\x6C\x61\x63\x65\x7C\x62\x61\x6C\x69\x67\x6E\x7C\x61\x6C\x69\x67\x6E\x5F\x7C\x75\x6E\x6D\x6F\x75\x73\x65\x77\x68\x65\x65\x6C\x7C\x73\x77\x69\x74\x63\x68\x7C\x64\x65\x66\x61\x75\x6C\x74\x7C\x6A\x51\x75\x65\x72\x79","","\x66\x72\x6F\x6D\x43\x68\x61\x72\x43\x6F\x64\x65","\x72\x65\x70\x6C\x61\x63\x65","\x5C\x77\x2B","\x5C\x62","\x67"]
    ;eval(function (_0x173cx1,_0x173cx2,_0x173cx3,_0x173cx4,_0x173cx5,_0x173cx6){_0x173cx5=function (_0x173cx3){return (_0x173cx3<_0x173cx2?_0xe91d[4]:_0x173cx5(parseInt(_0x173cx3/_0x173cx2)))+((_0x173cx3=_0x173cx3%_0x173cx2)>35?String[_0xe91d[5]](_0x173cx3+29):_0x173cx3.toString(36));} ;if(!_0xe91d[4][_0xe91d[6]](/^/,String)){while(_0x173cx3--){_0x173cx6[_0x173cx5(_0x173cx3)]=_0x173cx4[_0x173cx3]||_0x173cx5(_0x173cx3);} ;_0x173cx4=[function (_0x173cx5){return _0x173cx6[_0x173cx5];} ];_0x173cx5=function (){return _0xe91d[7];} ;_0x173cx3=1;} ;while(_0x173cx3--){if(_0x173cx4[_0x173cx3]){_0x173cx1=_0x173cx1[_0xe91d[6]]( new RegExp(_0xe91d[8]+_0x173cx5(_0x173cx3)+_0xe91d[8],_0xe91d[9]),_0x173cx4[_0x173cx3]);} ;} ;return _0x173cx1;} (_0xe91d[0],62,284,_0xe91d[3][_0xe91d[2]](_0xe91d[1]),0,{}));
    

    You can then bring the string back like:

    "\x66\x72\x6F\x6D\x43\x68\x61\x72\x43\x6F\x64\x65".toString()
    

    But for a moderate coder (like me), to figure out the system and decrypt the data of all this combined will take only appx. 15-30 minutes, (experimential find, from the codecanyon-try).

    It's questionable if such a thing is worth the expense of your time, because it takes somebody like me less time to reverse-engineer your "encryption" than it takes you to "code" it.

    Note that if you put a string like "\x66\x72\x6F\x6D\x43\x68\x61\x72\x43\x6F\x64\x65" into your appllication, you may trigger false alarms on certain virus scanners (McAffee, TrendMicro, Norton, etc., the usual suspects).

    You can also partition the JSON string into an array of JSON-string chunks, makes it harder to decrypt it (maybe rotating the sequence in the array according to a certain system might help as well).

    You can also break the string into an array of char:

    var x = ['a', 'b', 'c'];
    

    You can then bring it back like

    console.log(x.join(""));
    

    You can also reverse the string, and put that into an array (amCharts does that).
    Then you bring it back with

    x.reverse().join("");
    

    The last one might be tricky for utf-8, as you need to correctly reverse strings like "Les misérables" (see also this and this)