- Blog Xebia France - http://blog.xebia.fr -

Java en Production – L’audit

Posted By Cyrille Le Clerc On Mercredi 25 août 2010 @ 12:40 In Exploitation,Java / JEE | 16 Comments

Après avoir abordé la gestion des fichiers de logs, nous continuons aujourd’hui la série « Applications Java prêtes pour la Production » avec l’audit.

Par audit, nous entendons l’audit des actions importantes réalisées sur une application.

Pourquoi auditer ?

Est-il vraiment utile de générer des informations d’audit dans nos applications ? Sans explications de juriste, quelques exemples suffiront à nous en convaincre :

  • Un site web de partage de photos doit pouvoir dire qui a uploadé quelle image, depuis quelle adresse IP et à quelle date.
  • L’application d’administration d’un site de e-commerce doit tracer toutes les modifications de prix pour empêcher un employé astucieux de baisser à 1 euro le prix de son téléphone préféré le temps de passer commande.

Pour revenir à des explications plus théoriques, les logs d’audit nous apportent :

  • les informations nécessaires à la justice en cas d’infraction,
  • la détection d’intrusions,
  • la reconstitution des événements en complément des logs d’exceptions pour aider au diagnostique de problèmes.

Nous nous placerons dans le cas le plus fréquent où nous ne développons pas d’outil pour consulter ces informations d’audit et où un accès direct au média de stockage (grep sur fichier texte, sql sur base de données, etc) suffit.

Que faut-il auditer ?

Dans un monde idéal, le contenu des messages serait défini avec les équipes de sécurité. En pratique, nous sommes assez seuls pour les choisir et il ne faut pas dramatiser. Si l’on ne prend pas le sujet à la légère, après quelques itérations, notre bon sens est le plus souvent suffisant.

Les éléments clefs à tracer sont :

  • L’heure exacte : il est essentiel que les serveurs soient à l’heure pour corréler les logs des différentes briques du système d’information. Le sujet est aujourd’hui censé être banal pour les équipes système (c.f. NTP) et nous pouvons demander le soutien des équipes sécurité pour obtenir gain de cause.
  • L’action réalisée : il s’agit souvent du nom de la méthode métier appelée.
  • L’identifiant et/ou la valeur des données métier sensibles manipulées : souvent les id ou le toString() des paramètres d’appel.
  • L’auteur de la manipulation : nom de l’utilisateur connecté et son adresse ip (pour plus de détails sur l’adresse ip : XForwardedFilter et Tomcat : Adresse IP de l’internaute, load balancer, reverse proxy et header Http X-Forwarded-For).
  • La description succincte des exceptions levées pour analyser les éventuelles attaques.

Pourquoi les logs d’accès des serveurs http ne suffisent pas ?

La première idée serait de se contenter des logs d’accès des serveurs web et des firewalls pour auditer les accès à nos applications ; nous n’aurions alors plus rien à faire.

Hélas, cela n’est pas suffisant car il manque dans les logs http des informations clefs :

  • Nous n’avons pas l’identité de l’appelant : on a bien l’adresse ip mais pas le login de l’utilisateur authentifié.
  • Nous n’avons pas les id passés en paramètre des opérations à auditer (sauf si on fait du REST) ; en SOAP, nous n’avons même pas le nom de l’opération !
  • Nous n’avons pas le détail des exceptions levées par l’application.

API : Framework de log vs. framework dédié

Dans un monde idéal, le framework d’audit ne devrait pas dépendre de la configuration des logs pour ne pas risquer qu’une mauvaise manipulation de ces configurations de logs ne le désactive.

En pratique, les frameworks de logs sont les briques les plus performantes et les plus matures pour traiter les besoins d’écriture d’audit et la probabilité de désactiver l’audit en faisant une mauvaise manipulation sur la configuration des logs est négligeable. Ces raisons nous amènent à utiliser SLF4J avec logback ou log4j pour gérer l’audit.

Nous encapsulerons tout de même le logger avec une couche légère packagée dans la librairie Xebia Spring Security Extras qui ajoutera au message l’identité de l’internaute et son adresse IP (via Spring Security). Cette librairie offre une gestion déclarative de l’audit avec une annotation @Audited, son aspect associé AuditAspect et une classe utilitaire Auditor. Nous ne rentrerons pas dans le débat annotations vs. code ; dans la majeure partie des projets, nous avons pu traiter la plupart de l’audit avec une annotation et seuls quelques cas ont nécessité de passer par du code.

Exemple de gestion de l’audit avec l’annotation @Audited :

@Audited(message = "transferMoney(#{args[0].accountNumber}, #{args[1].accountNumber}, #{args[3]})")
public void transferMoney(Account from, Account to, Amount amount) throws BusinessException { ... }

L’attribut message est un pattern supportant Spring Expression Language définissant l’entrée insérée dans le fichier d’audit ; la date, le nom de l’utilisateur, l’adresse ip et l’exception s’il y en a une sont ajoutés au message.

Fragment de configuration Spring Framework pour utiliser l’annotation @Audited :

<beans ...
   xmlns:security-extras="http://www.xebia.fr/schema/xebia-spring-security-extras"
   xsi:schemaLocation="...
        http://www.xebia.fr/schema/xebia-spring-security-extras http://www.xebia.fr/schema/security/xebia-spring-security-extras.xsd">
   <!-- enable Spring AOP -->
   <aop:aspectj-autoproxy/>
  <!-- activate the AutitAspect -->
  <security-extras:audit-aspect />
   ...
</beans>

Message d’audit généré :

... transferMoney(000652584515, 0000684651684, 187.53) by bdupont coming from 192.168.0.14
... transferMoney(000652584515, 0000684651684, 666666.00) threw '...BusinessException: debit amount greater than account balance'
   by bdupont coming from 192.168.0.14

Exemple de gestion de l’audit avec l’utilitaire Auditor :

public void transferMoney(...) throws BusinessException {
   ...
   Auditor.audit("Tranfer '" + amount + "' from " + fromAccount + " to " + toAccount);
}

Message d’audit généré :

... Transfer '187.53 euros' from Account[000652584515] to Account[0000684651684] by bdupont coming from 192.168.0.14

L’entrée d’audit est ajoutée dans un fichier d’audit géré par le logger spécifique "fr.xebia.audit" (voir cet article pour la configuration du logger).

Tous les détails sur l’annotation @Audited sont sur @Audited Annotation.

Intégration du framework dans une application

Ce framework peut être intégré de différentes façons dans une application :

Stockage : fichier texte vs. base de données

Le stockage des entrées d’audit en base de données permet sûrement une recherche plus fine des données que sur des fichiers mais cela ajoute de la complexité (déploiement, exploitation, backup) ainsi que des risques de pannes et impacte les performances. Les approches JMS présentent des contraintes similaires et l’utilisation de systèmes de logs distants comme rsyslog présentent un défi de fiabilité. Ces difficultés sont accentuées lorsqu’une application génère de gros volumes de logs (plusieurs Go/jour).

Pour ces raisons, nous préférons stocker les messages d’audit dans un simple fichier. Les risques de saturation du système de fichiers sont assez facilement gérables par les équipes d’exploitation, les procédures d’archivage et de consultation très simples (gzip, scp, grep, etc) et il n’y a quasiment jamais de problème de performance, même avec des fichiers de quelques Go par jour.

Y-a-t-il un plus grand risque de perdre les données par de mauvaises manipulations ? Si une application est critique, les exploitants doivent déjà ne pas perdre les fichiers de log du système d’exploitation, des serveurs web et autres firewalls.

Pour la gestion des messages d’audit sous forme de fichier texte, nous aimons logback comme nous l’avons expliqué dans Java en Production – Les fichiers de logs mais il est aussi possible d’utiliser Log4j.

Exemple de configuration Logback pour gérer les messages d’audit émis sur le logger fr.xebia.audit :

<appender name="audit-file" class="ch.qos.logback.core.rolling.RollingFileAppender">
   <file>${LOGS_FOLDER}/my-application-audit.log</file>
   <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <!-- rotate every day -->
      <fileNamePattern>/my-application-audit.%d{yyyyMMdd-HHmm}.log.zip</fileNamePattern>
   </rollingPolicy>
   <encoder>
      <!-- don't output the date or the logger name because the auditing framework handles this -->
      <pattern>%m %throwable{0}%n</pattern>
   </encoder>
</appender>
<!-- route the 'fr.xebia.audit' log messages to the audit-file -->
<logger name="fr.xebia.audit" additivity="false" level="TRACE">
   <appender-ref ref="audit-file" />
</logger>

Exemple équivalent avec log4j (le EnhancedPatternLayout requiert log4j 1.2.16) :

log4j.appender.auditfile=org.apache.log4j.DailyRollingFileAppender
log4j.appender.auditfile.datePattern='-'yyyyMMdd
log4j.appender.auditfile.file=${catalina.base}/logs/my-application-audit.log
log4j.appender.auditfile.layout=org.apache.log4j.EnhancedPatternLayout
log4j.appender.auditfile.layout.conversionPattern=%m %throwable{short}n
log4j.logger.fr.xebia.audit=INFO, auditfile

Que faire des logs d’audit après les avoir générées ?

Nous ne rentrerons pas plus dans les détails de la gestion des logs d’audit après leur génération par nos applications.

Ce sujet complexe présente aussi bien des aspects juridiques que de confidentialité ou encore de fiabilité. Schématiquement, on n’a pas le droit de garder indéfiniment des données personnelles, il faut restreindre leur consultation et empêcher leur modification et leur destruction par accident comme par malveillance.

Des professionnels de l’exploitation et de la sécurité sont beaucoup plus compétents que nous sur ce sujet :-) .

Pour aller plus loin

Si le traitement de l’audit dans les applications vous a intéressé, nous avons aimé lire :

Synthèse

Nous avons vu aujourd’hui une façon simple de gérer l’audit d’applications java en reposant sur le framework de log de l’application (Logback voire Log4j) pour écrire les messages dans de simples fichiers texte avec une surcouche très légère composée d’une annotation @Audited et d’un utilitaire Auditor.

Historique
25/11/2010 : passage à la version 1.1.5 de la librarie xebia-spring-security-extras avec utilisation du namespace de configuration.
20/12/2011 : xebia-spring-security-extras : passage à la version 1.1.6 et aux URLs GitHub


Article printed from Blog Xebia France: http://blog.xebia.fr

URL to article: http://blog.xebia.fr/2010/08/25/java-en-production-laudit/