beeware / briefcase

Tools to support converting a Python project into a standalone native application.
https://briefcase.readthedocs.io/
BSD 3-Clause "New" or "Revised" License
2.47k stars 350 forks source link

Add a packaging option to minify or otherwise obfuscate the python code in the distribution package #1865

Open michelcrypt4d4mus opened 3 weeks ago

michelcrypt4d4mus commented 3 weeks ago

What is the problem or limitation you are having?

Applications built by briefcase store all the python code (both for the app and included packages) in cleartext in (almost) the same hierarchy you see when you're the developer of the application. That both makes the packaged application bigger on disk than it needs to be and also makes it trivial for any user of the app to just browse the folder of the app they installed and see all the code. It would be nice if there were some options to allow obfuscation of that code so this weren't quite so easy.

Describe the solution you'd like

There could be an option in pyproject.toml called something obfuscation_level that could specify which approach to use when packagin up the app. There's three different options I can think of from the jump:

  1. minification (which could be considered the least severe form of obfuscation) just strips comments and docstrings and shortens variables and functions and thus reduces the size of the final distribution (e.g. Python-Minifier)
  2. compiling to bytecode is a pretty reasonable way to obfuscate, especially if you also marshal and compress that bytecode with zlib or do some other obfuscatory thing
  3. at the extreme end there's tools like pyarmor which has a whole host of options that range up to the truly extreme attempts to make life hellish even for highly skilled reverse engineers

Describe alternatives you've considered

If you develop most of the logic in your briefcase app as a package such that briefcase imports the vast majority of the functionality via pip install from a private pypi or git repo you can apply these tools to the code, commit or release that obfuscated/minified version, and then have briefcase install it just as it would any other package.

edit: i have actually gotten this approach to work successfully (with pyarmor as the obfuscation tool) for my own briefcase app.

Additional context

Obviously there are some restrictions here around open source licenses. For instance if your briefcase app relies on a package licensed under the GPL then you are supposed to release the source code and so obfuscation of the code in the final application should not be allowed.

freakboy3742 commented 3 weeks ago

My experience has been that while some developers are very keen about code obfuscation, the tools are (a) not actually necessary for novice developers, and (b) not actually protection against a determined attacker.

Ultimately, code (especially something like Python code) needs to be executed; if you want someone to use your code, you have to give it to them. I've seen first hand code that was written in C, and was distributed as an obfuscated binary, and it was still a relatively minor exercise to reverse engineer the "interesting" part of the code (in this case, the code that implemented license validation 😄).

Code obfuscation is also somewhat opposed to the fundamental philosophy of FLOSS movements in general. This is especially important when you consider that this is a feature that is most likely to be requested by commercial users of Briefcase - so we'd be adding and maintaining a feature that is mostly useful for commercial users, with no particular benefit to the volunteers that maintain the (open source) code for the project.

However, I'm also aware that not all software developers share my pessimism about the usefulness of obfuscation, and I don't want to render Briefcase inappropriate for those users that have a requirement to use obfuscation of some kind.

So - my inclination is that this is the sort of feature we should support by an extension API. If we were to add a "build plugin" API, users could define steps that they want to be executed as part of the build process, including (but not limited to) obfuscation techniques.

The "dogfood" use for this interface could be the current __pycache__ stripping process. We moved that code to a plugin, and then added a project setting that defines the post-processing plugins to use as part of the build (and, if the setting isn't defined, fall back to the default __pycache__ stripping).

This would allow us to prove the plugin interface works; it would then be up to third-party developers to contribute other "post processing" steps - this could be:

or anything else someone might need to do.