Click or drag to resize

How To use declarative obfuscation in applications

This topic is about obfuscation and how it integrates with Packflow applications' deployment flow.

Introduction

Obfuscation is the practice of making an assembly resilient to retro-engineering by obscuring the embedded code.

While often discarded by the community, declarative obfuscation in conjuction with assembly signing may harden protection against technology theft or unwanted code alterations. See this section for details.

However, it can't be considered as a security layer in itself. It is a way to raise the cost of retro-engineering.

When to use it

Obfuscation makes sense if your assemblies have to be delivered and left away of your control.

Hosting a customer's application in your own trusted environment (SAAS) makes it unecessary.

Below is a summary of different security needs, and what obfuscation can provide in these cases.

Situation

Is obfuscation suitable ?

Details

Prevent copy-paste of an assembly for alteration or theft.

Yes

While probably still retro-engineerable, obfuscated assemblies expose codes that often need transformation. They don't build easily, and are difficult to maintain.

If an application is made of several signed assemblies, trying to replace one may require replacing the whole dependency chain, because of signature mismatches. While still possible, code alteration becomes very costy in this context.

Note Note

It is possible to promote two-way signature verification to enhance this principle. See this article for details

Protect licensing code.

Yes

When present, licensing code does always better obfuscated.

Compacting the assembly.

Yes

Symbol renaming is a good way to compress the IL code drastically.

If package size is a serious concern, obfuscation might help reducing the Dll size.

Note Note
In a Packflow generated application, most package space is occupied by generated .js or aspx files, which can't be obfuscated.

Hide credentials or other sensitive data in code.

No

Obfuscation fails at hiding strings or other data in assemblies. Set values runtime using configuration files or registry. Both can be encrypted.

Provide 'black-box' functionnality.

No

Over-obfuscated assemblies are quite suspicious by nature. Moreover, in case of an API like exposed in Packflow applications, obfuscation may impede client developers' work.

If a functionnality has to be totally black-boxed, deliver it through an online service and keep your assemblies private.

How to use it

You should always obfuscate codes in a selective way, for several reasons:

  • DI patterns, serialization, reflection and debugging are all affected by obfuscation.
  • IT actors quite often need to dig in an assembly to understand some component better. Being prevented doing so creates frustration and suspicion.

Following the principles below will help you avoid most common pitfalls.

  • Do not apply renaming/hiding to public members or types.

    Be carefull not setting too wide obfuscation rules. Renaming any public type will make it uncallable by Packflow Core. As all generated types are public in Packflow applications, renaming may only apply to internal types added in custom development.

  • Types loaded by reflexion have to be left clear.

    If types or members are to be called by reflexion in your code, avoid obfuscating those, as code won't find them runtime.

  • Serializable types are affected by obfuscation

    If serializing internal types, avoid obfuscation as serialized strings will contain encrypted types names, and may become unreadable. Some propose to use attributes on members and types to set their serialized name, but why hiding something you re-flag with an attribute ?

  • Always keep track of your obfusaction seed.

    Obfuscation seed is a code governing obfuscation randomness. It is necessary to decipher stack traces. Always keep track of what seed what used for every version of your application, to ensure proper debugging later on.

Obfuscating Packflow applications

Packflow Manager ships open-source ConfuserEx obfuscation tool, allowing to easily obfuscate applications in a regular deployment flow.

This is made in two steps:

  1. Use standard .Net obfuscation attribute to declare obfuscation settings in code.

    In your application project, find internal types you want to hide, and decorate them with attribute. These are usefull to instruct the obfuscation engine on how to process the type.

    Two parameters have to be set to trigger obfuscation on the type:

    C#
    namespace internalNamespace{
    
          [Obfuscation(Exclude = false, Feature = "+constants;+rename")]
    
            internal class ClassToHide{
    
                    internal string PropertyToHide{ get; set; }
    
                    internal void MethodToHide(){ }                
            }
    }
    Note Note

    Please note obfuscation can be set globally to a namespace or assembly using an assembly-wise attribute, like below. These attributes are usually set in AssemblyInfo file, under /Properties/AssemblyInfo.cs, in your application project.

    C#
    [assembly: Obfuscation(Exclude = false, Feature = "namespace('internalNamespace'):+rename")]
  2. Activate Obfuscation when building package in Packflow Manager.

    Obfuscation 1

When building, Packflow Manager will automatically generate and use a ConfuserEx project in your application's project folder. It may be edited later using ConfuserEx graphical editor, to tweak or add custom settings.

Note Note

ConfuserEx's graphical editor is shipped with Packflow Manager. It can be found under Packflow manager's installation folder, for eventual tweaking of the generated project file. Declarative obfuscation has priority on project settings.

Default path is %PROGRAMFILES%\Mica-Systems\Packflow Manager\ConfuserEx\ConfuserEx.exe

Caution note Caution
In Packflow Manager, obfuscation can be enabled when deploying in release configuration only.
Why is obfuscation mostly discouraged by the community

Searching Google or StackOverflow for advices about obfuscation is often challenging as many discussions take place in a poorly or non-scoped context. It is usually assumed that one wants to obfuscate a whole component, in order to hide the application's inner working and structure. This rarely makes sense in a Packflow scenario.

In such posts, people often rush to convince obfuscation is a useless and superceded practice, by enumerating drawbacks and pitfalls associated with it, sometimes wihout much comprehension of what happens behind the scene. Not much distinction is made on what the component does, how it relates to other assemblies, and what clients expect from it. Usually, architectural security gains are not considered.

It is also quite often heard that this practice is simply useless because transformed codes can still be read from the assembly. Well, an operating system couldn't run a strictly unreadable assembly. This argument comes again from the flawed assumption that successfull obfuscation should hide all the component's logic.

These writings mostly emanate from developers, whose get usually no benefit from obfuscation, while they have to support their drawbacks. It makes their job more difficult, via induced bugs and scrambled stack traces. This conjuction of factors induces strong negative bias against obfuscation.

We do think differently. We consider declarative (partial) obfuscation backed with assembly signing as a good way to harden protection against technology theft, while letting legitimate actors decompile relevant parts of the code.

How ? By making the use of a retro-engineered component a serious burden.

Imagine this scenario: Someone wants to retro-engineer and re-build an obfuscated and signed application dll from your company. As long as it works on its own, there is no notable difficulty doing it. But, if that dll is signatured-checked by other necessary components, it makes it mandatory to re-build every assembly in the dependency chain, because of signature mismatches.

A partial obfuscation of every assembly in the chain will add serious effort to succeed in this project, as every code will need tweaking in order to be built properly. If the architecture is complex enough, and all dlls are partially obfuscated, this task becomes much more cumbersome than when no obfuscation is present. This may discourage even expert attackers, if the cost of the attack becomes too high. Moreover, these codes are difficult to maintain.

As you can see, Obfuscation may play a serious role in your application's security, as long as the architecture makes it applicable.

Wheter obfuscating is worth the trouble or not needs serious analysis, and should be evaluated in confuction with architects and designers.

See Also