« Obfusquez-vous ? » Saison 2

le 01/03/2010 par Eric BÉrenguier
Tags: Software Engineering

Le premier article a illustré le fonctionnement des outils d'obfuscation sur quelques exemples concrets. Le présent article va proposer des bonnes pratiques pour réussir la mise en place d’une solution d’obfuscation dans un projet.

Un 3ème article prendra plus de recul et dressera la liste des questions à se poser avant de lancer un tel projet :

  • Dans quel cas est-il pertinent d’utiliser un outil d’obfuscation (et quand est-ce qu’il ne faut surtout pas en utiliser) ?
  • Quels sont réellement les gains d'un tel outil ?
  • Comment choisir un produit d’obfuscation ?
  • Quelles sont les solutions alternatives ?

Les limitations de l’obfuscation

L’utilisation des outils d'obfuscation amène rapidement à l’identification de limitations ou de contraintes. En voici les principaux points d’attention (cette liste n’est pas exhaustive) :

Réflexion

Les mécanismes de réflexion (ou introspection) ne sont pas supportés (puisque les symboles sont renommés). Une application qui les utilise ne fonctionnera pas une fois "obfusquée". Par exemple, un code aussi simple que cela produira des logs illisibles :

Logger monLogger = Logger.getLogger(this.getClass());

Pour éviter ce problème, il faut paramétrer manuellement des exceptions (c'est-à-dire des noms de symbole qui ne seront pas modifiés) au niveau de l'outil d’obfuscation. Un autre exemple est lié à l’utilisation de frameworks d’IOC type *Spring*. Le paramétrage de l’outil d’obfuscation peut vite devenir complexe. Et si on laisse tous les beans et méthodes publiques appelés en clair dans le code, on peut se poser la question de l’utilité de l’outil d’obfuscation. En théorie, on pourrait écrire un obfuscateur de code Spring (c'est-à-dire qui modifie les noms de beans / méthodes et les fichiers de configuration Spring), mais je n’en ai pas trouvé sur étagère. Il faut bien noter qu'il n’existe pas de moyen automatique de vérifier si le paramétrage de l’obfuscateur est correct. Une erreur se traduira probablement par un ClassNotFoundException à l’exécution. D’où l’importance de ne pas négliger les tests.

Intégration de code

Un projet fournit à un autre projet une bibliothèque de fonction obfusquée pour être intégrée. Comment peut-on appeler du code obfusqué ? Certains outils proposent des fonctions permettant d’adresser ce problème avec une fonction (parfois appelée « library mode ») qui ne modifie pas les noms de classe ou méthodes publiques. Malheureusement, cette fonction rend l’obfuscation beaucoup moins efficace (quand on a les getters/setters en clair, on a vite fait de donner aux attributs privés un nom explicite avec un « clic-droit + rename »). Cette approche est donc à éviter et on recommande plutôt de paramétrer l’outil pour ne pas modifier les points d’entrée (cf. partie paramétrage dans cet article). D’autres outils proposent des fonctions d’ « obfuscation incrémentale » mais elles impliquent de livrer des fichiers de mapping avec le code obfusqué et d’utiliser à nouveau l’outil d’obfuscation sur le code appelant. Cela fonctionne mais la mise en œuvre en est plus compliquée.

Diagnostic en production

L’application se plante en production, les stack-traces et dumps de VM ne sont plus lisibles et le debugger ne fonctionne plus. Est-ce acceptable ? Heureusement certains produits fournissent une solution sous la forme de fichiers de "reverse mapping" (qui permettent d'inverser l'effet de l'obfuscation). Mais il faut mettre en place un versionnage de ces fichiers, les mettre à disposition des utilisateurs (développeurs, équipe support…) et surtout les protéger  (ils permettent de retrouver le code « en clair » à partir de la version obfusquée).

Performances

En théorie les outils avancés (mise en oeuvre de string obfuscation ou control-flow obfuscation) pourraient avoir des impacts négatifs sur les performances. En pratique je ne l’ai pas constaté, même sur des applications consommatrices en temps de calcul (applications « CPU intensive »).

Quelques bonnes pratiques de mise en œuvre

Les tests

Il ne faut pas attendre la mise en production pour tester l'application "obfusquée". L'idéal est de produire un build le plus souvent possible (au moins une fois par jour) et de le tester. C’est plus facile si on a des tests d'intégration ou fonctionnels automatisés. Heureusement, l'intégration des outils d'obfuscation à son « usine de développement » est en général peu complexe (une tâche en plus dans le processus de build).

Le paramétrage des outils

Il faut au maximum s’appuyer sur des règles pour identifier les parties de code à ne pas obfusquer : on peut utiliser par ordre de préférence soit :

  1. Des conventions de nommages (paramétrées au niveau de l'obfuscateur) ;
  2. Des annotations dans le code.

Il faut absolument proscrire les outils qui demandent à l'utilisateur de cliquer séparément chaque élément de code à laisser en clair (c’est une opération manuelle). Lors de la prochaine release, on est sur de se planter !). Il peut être pertinent d’intégrer dans son « build » quotidien une vérification des règles s’appuyant sur des conventions de nommage (« pattern testing »).

Exemple : J’ai des « DTO » que je sérialise pour les transmettre à une autre application. Je dois donc les mettre dans un package .dto, et ils implémentent tous une interface. L’outil d’obfuscation s’appuie sur cette règle (donc une seule règle à paramétrer, pas de modification quand je crée un DTO). Le build va lever une alerte si des DTO ne sont pas dans le bon package pour réduire les risques d’erreur. On peut aussi vérifier qu’il n’y a pas d’autres « implements serializable » dans le code.

Si on veut aller plus loin, on peut :

  • Mettre en place un processus de suivi du paramétrage de l'obfuscation : est-ce qu'on a des règles obsolètes ? Est-ce que les développeurs connaissent bien toutes les règles ... Cela peut par exemple passer par des revues périodiques de code et de la configuration.
  • Gérer le paramétrage de l’outil d’obfuscation dans la gestion de configuration avec le code de l'application.

En conclusion

En espérant que cet article vous aidera à réussir votre projet d’obfuscation, ne manquez pas le prochain où on reviendra à la question initiale : « pourquoi vous obfusquez ? » (i.e. quels sont les cas business d’application de l’obfuscation ?)