packaging support for appjs #239

Open
wants to merge 3 commits into
from

Projects

None yet

5 participants

@sihorton
Contributor
sihorton commented Nov 7, 2012

This patch modifies the example application so that if you pass it an argument with a path to a .appjs file then it should run the application from inside the package. The majority of the logic is provided by appjs-package module.

npm install appjs-package in the root directory to get the latest implementation.

I have tested extensively on windows and have example apps you can test it with here: http://appjs.delightfulsoftware.com/example-apps/

/Simon

Simon Horton added some commits Nov 7, 2012
Simon Horton Modified hello world to use the appjs-package implementation. Added a…
… package.json since this is required for application packaging. Modified build process to copy over package.json to destination application.
1cec231
Simon Horton updated package.json so it contains correct modules out of the box. c90a712
Simon Horton find abs path to script location and launch node and app.js relative …
…to that path. This fixes problems where you run the script from a different working directory. Without the fix the script fails if it is run from another location. This fix is needed to support running .appjs files from anywhere on the computer.

Passed first command line argument into app.js (this is needed to pass the script the name of the .appjs file to run.
d33dc23
@sihorton
Contributor
sihorton commented Nov 8, 2012

I have made further improvements to the packaging system which can land in a later pull request. I now transparently deflate / inflate with gzip for network transmission of the module files.

@MisterRichardson

Sihorton,

I haven't started studying on your packaging solution, could you comment how could one try to hide part of the code in a encrypted manner that can only be accessed when the correct key is applied?

I want to hide functionality of the application that should only be available with the correct authentication, and of course don't want a cracker to easily find out how I'm doing it.

Any pointer on the subject will be helpful.

Thank you.

@sihorton
Contributor
sihorton commented Dec 3, 2012

I have done 2 full rewrites of the packaging functionality after submitting this patch so the overall design has improved a large amount. My npm modules are more up to date and I will be releasing the next generation very soon. Sorry for the long comment but I have discussed these issues back and forward with various people. Here is my thinking:-

The out-of-the-box appjs package format is going to be open, you will be able to view the contents of the package in a hex editor, and since the project is open source whatever "magic" is used will be open for anyone to view on github and figure out how it works. It is relatively simple to take the code I have written and add a layer of encryption and decryption or public / private keys. That would be as secure as the algorithms that are used (openssl). The problem is that you will need to ask for the private key or password to unlock the contents of the package and if that is happening on the end users machine in an open source project then you are not going to be able to hide what you are doing. If you want for example to save all of your passwords into a file, encrypt it and then save it to disk. Then you can use the crypto module for nodejs and that will work reasonably well. The user would then need to enter in a password to unlock the data. Likewise if you want code signing with a private key and then verification using a public key of the person that signed the code then that is also possible with the nodejs crypto libraries.

I have been asked similar questions by a number of other developers when they heard about the package format. What they want is to take an appjs application, package it up and then run it on the end users machine without it being "open on the disk" as it is now. So for example you write visual basic or delphi applications and then the compiler puts out an executable file that does not have all of the source code attached like appjs has. The problem with trying to do this with javascript is that javascript is highly dynamic and therefore if you take a function and call function.toString() then you will get the source code back of that function.

So if you want to develop a solution yourself then the answer is basically to write parts or all of the application as C or C++ node_modules. These can be installed alongside your application and can then hold logic in them that is not open like javascript. Obviously the downside of that is that it is generally many times slower to develop in C and that is why appjs is being used.

If your aim is to defeat the crackers that are able to crack microsoft office and windows -- products made by a billion dollar company then that is very difficult to ever achieve. Also delphi and visual basic application can be reverse engineered and their source code returned to a certain degree. The same is possible with java and C programs if you search long enough and put in enough effort.

Having said all of that I am still an engineer and generally like a challenge so have tried thinking through the problem and built a couple of prototypes. What I was able to do is create a modified nodejs binary that is able to run "scrambled" packages. Basically security by obscurity. Then by not releasing the source code of the modified version and not releasing the source code of the packager but only supplying binaries you put up a wall that will mean someone will need to poke around and try to figure out what you are doing in order to get back the source code. Hopefully that is enough that you have a more "commercial" package that does not leave all of the code on disk so it is more possible to sell. Obviously if a large amount of resources /expertise are expended to get the code then eventually it will break, but at the same time the same amount of resources / expertise could just develop an app better than the one you are developing so it is a zero sum game.

I have had a number of conversations with people and this represents my latest thinking. What do you think? Is there an "open" way to hide the source code? Anything I am missing. Obviously if you want to discuss details then best to do it over chat or private messages rather than on github :-) Lots of people have asked me about it though so good that I write a full answer here!

@juzerali
juzerali commented Jan 8, 2013

In the past I have also tried searching for a way to create nodejs binaries. Nodejs team believes it is possible but they won't delve into that. I searched a little more but found nothing. I have given up now.

💯 for Basically security by obscurity , I have seen Java and even C++ getting decompiled to an extent that the program can be reproduced after putting in a decent amount of effort.

@sihorton
Contributor
sihorton commented Jan 8, 2013

It is possible to include your own modules into the nodejs build process. Doing this causes javascript modules to be compiled to machine code and then included in the binary. Doing the classic .toString() javascript function then returns:
[Native Code]
So the build process has "lost" the original javascript source code and it is no longer available. By including your own code into the binary then you can call that from a script that you are running to do decryption. This works exactly the same as the built in nodejs modules, you just add your own module.

Using such a native code function you could then read in files and decrypt them or you could take core / key algorithms and place them directly in the binary. This represents quite a good way to go about packaging what would otherwise be open source files.

It still relies on security by obscurity.

@juzerali
juzerali commented Jan 8, 2013

Yes, I am aware of packaging native modules in nodejs. What I meant by nodejs binaries was to obscure the javascript code itself, which, by far, I haven't seen.

@sihorton
Contributor
sihorton commented Jan 8, 2013

Maybe you are looking for something like: https://github.com/crcn/nexe "create a single executable out of your node.js apps".

@YurySolovyov

v8 snapshot?

@neatcode

I think the simplest way to protect the Javascript source code of a desktop application is to do the same thing we do for internet-based Javascript applications (front ends): minify the source before distributing the application, regardless of how it's packaged. Even better if you can minify the libraries your application uses with / at the same time as you minify your application's main source files. Most function names and variables will appear, after minification, like: b3(a4,g8,j8), var b8, var d9 = i77, ca32(), a5 = z2(a4,g8). This will make your source code largely useless EVEN IF the "attacker" recovers your source code and gets it to compile into a working application. Making modifications becomes much more difficult (I've tried this with internet-based Javascript front-ends that have been minified), to the point it's almost useless except for the most basic of modifications. It would usually be simpler to rewrite the whole program from scratch in order to make modifications and resell it, than to modify an existing "minified" one from the minified source to try to make a new product and sell it.

If you want a hacker-proof program beyond that, however, whether using Javascript or c++ or anything, your best bet is to make key functionality of your program only accessible over the internet and keep your (probably best minified) source for that key functionality exclusively on your own server. The app would function as a normal desktop app except for when certain key functionality is needed, then it would query your server online for the calculation. For example, Microsoft Word could make it so that whenever a table is created or resized or edited, the source that describes how to modify the table could be on Microsoft's server, and Microsoft Word would have to make a round-trip to the server to get the data for how to update the table. When the server is contacted, the software would, for example, send its Serial Number for verification alongside its data to be modified. Serial Numbers that are invalid or reused would be rejected, and the table would not successfully update, though other parts of the program may continue to work.

This last method is nearly fool-proof if you can guarantee the security of the server. One important thing to note is that it is key that the algorithm for producing Serial Numbers for your application is highly secure and can't be guessed or derived. In fact, I'd generate them from a "true" random number generating source such as a quantum random number generator, and keep a record of the ones you've produced for distribution on a server and make sure they're well guarded.

Still, I highly recommend minifying the source code for Node.js desktop apps. This should be adequate even for enterprise-level software.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment