Published on June 18, 2020 by Alexander Goodwin
In this post, we will share a few experiences we learned during the making of JSDefender.
Using an Open-Source Obfuscation Engine
As the weeks went on, we became more and more disappointed. We found only a few well-maintained projects, and the majority of them had issues that did not meet our quality expectations.
Our main concerns were:
- Though we had a good impression of the code base, taking ownership, fixing the open issues, and implementing missing features would have taken too many resources.
- Our gut feeling told us that the number of unit test cases in Timofey’s project (it was about 1200 that time) seemed too few compared to the nature of the task to solve. We were concerned about what we would find as we implemented heavier testing.
Let me mention just one of them.
About 15 months later, as we are preparing to release JSDefender v2, we still believe we made the right decision. After the continuous refactoring from the start of the project, we have clean code and low technical debt. We’re rarely affected by security fixes in other packages (so far, almost all of them have been in packages that we use in our build process).
Focusing On the Right Feature Set
Choosing the Right Protections
As humans, we prefer to read straightforward code with many clues such as comments, intuitive identifiers, self-describing method names, well-organized control flow, and many others. Everything that adds semantics to the code helps our understanding. On the contrary, things that remove semantics hinder us from getting acquainted with the details and intent of a program.
- How will the length of the source code increase?
- It cause significant performance degradation?
- Is it possible to reverse this transformation?
- Can it be reversed with a tool?
- How easy is it to change the transformed code back to something easier to read and understand?
- What level of pain or frustration does it cause?
- Can the transformation break running code?
- Is the transformation easy to implement, test, and support?
The 80-20 Rule
The 80-20-rule guides us in another way. When measuring the performance consequences of particular obfuscation techniques, we observed that the overall performance gets orders of magnitudes better if we use partial protection. In other words, if performance is a concern, JSDefender can protect just the parts (“20 percent”) of the code that contain significant intellectual property or are otherwise sensitive to attack, while leaving the remaining code (“80 percent”) intact. The ultimate balance is up to you. This is why we designed JSDefender with highly granular configuration and partial protection in mind from the start, so when we create a new protection technique or modify an existing one, we do not need to focus on the partial protection aspect. When we implement the algorithm of the transformation, the engine takes care of managing which parts of the input code to transform, and which parts to leave alone.
Providing Quality in Development and Support
The JSDefender team believes that excellent software can be delivered only by keeping the technical debt at a very low level. Automated testing, continuous refactoring, code reviews and pair programming, and regular in-team knowledge sharing is a part of our everyday work.
When examining the source code of several open-source projects, though we acknowledge the excellent quality of some of them, we did not feel that we would be confident enough to apply our best practices and approach with those particular projects.
Pain or Gain?
Let me tell you a story about testing, when we were building the C# proof-of-concept.
From an external point of view, you may think that using C# and then moving to TypeScript later was an unnecessary waste of resources. The team had to port not only the actual code but also the test cases to the new programming language. We saw it differently. With the C# prototype, we learned two important things that were extremely useful by the time we wrote the first TypeScript code lines:
- How we can carry out particular transforms
- What we should test to prove that they work as expected
Because of these lessons, creating the TypeScript code base — I deliberately do not say “porting” — took less than 20 man-days.
In a couple of weeks, the number of our automatic test cases will exceed 10 thousand.
First, we use dogfooding. The first enormous test is JSDefender itself — one of the last steps in our build-chain is JSDefender protecting its source with itself. We use Webpack, and the code contains an internal Webpack plugin that uses the current build of the source to obfuscate the current build. If we have a bug, there’s a high likelihood that JSDefender will fail as we try to run it.
The code is about 1.5 Mbytes. It runs tests in about 40 seconds and measures a few things. The first figure shows a successful test case with low performance degradation, while the second indicates too high performance penalty:
On-Premises Tool vs. Cloud Service
- Doesn’t keep your original source code (even for future testing), or if they do, has documented access control and retention policies that you are comfortable with.
- Has proper controls in place on their services, to prevent, detect, and mitigate data breaches and leaks.
- Abides by the same laws and regulations you are subject to.
Engineering and development teams occasionally make mistakes — just as our team does. What if such an issue leads to the leaking of your unprotected code? Simply put, we know that many of our customers would rather not send their unprotected code to a service hosted somewhere beyond their control, run by entities they may not fully trust.
So, while understanding and admitting that there are reasonable cases for using an online code protection service, we emphasize the on-premises usage of JSDefender. Even if our engineering team makes mistakes, the impact of a potential bug is significantly less than in the online case, since our customers still have their infrastructure, policies, and controls in place to prevent sensitive code from leaving their premises.
You can get started with JSDefender by downloading a fully functional, time-limited trial copy. Trials come with full product support.
JSDefender is available as part of a PreEmptive Protection Team, Group, or Enterprise license and IS FREE to current subscribers at those levels. Standalone pricing is also available. To find out more, request a quote.
Our Online Demo version of JSDefender is also available with no sign-up needed!