Quantcast
Channel: Planeta Código
Viewing all articles
Browse latest Browse all 2721

Blog Bitix: Ofuscar datos sensibles en las trazas con Log4j

$
0
0
Java

Los archivos de trazas o logs contienen información de lo que ha realizado la aplicación. Estos registros de información contienen los datos que el desarrollador considera de utilidad en caso de necesitar su consulta. Algunos datos son especialmente sensibles ya que su obtención permiten acceder a cuentas de usuario, obtener datos como tarjetas de crédito o cuentas bancarias, contraseñas o bearer tokens de peticiones HTTP que autorizan el acceso. Proteger las contraseñas hasheandolas aún con salt y cifrar información por motivos seguridad y privacidad es inútil si luego esta información está presente en los archivos de log en texto plano.

Log4j es una de las librerías más utilizadas para añadir la funcionalidad de las trazas en una aplicación Java. Proteger algunos datos sensibles se puede hacer de varias formas. Una de ellas es hacer que sea la aplicación la que se encargue de no emitir estos datos en las trazas u ofuscarla enmascarándola al toda o parte. Para este caso se pueden utilizar objetos Message que adaptan los objetos de la aplicación a los datos a emitir en las trazas pero requiere modificar en todos los puntos de la aplicación.

En el siguiente ejemplo se hace uso de lookahead como se detalla en la clase Pattern de Java para añadir la funcionalidad de que los últimos caracteres queden visibles y la clase SecuredMessage aplica expresiones regulares al mensaje, en caso de encontrar una coincidencia realiza la ofuscación.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
packageio.github.picodotdev.blogbitix.log4j;...publicclassMain{privatestaticfinalLoggerlogger=LogManager.getLogger(Main.class);publicstaticvoidmain(String[]args){...logger.info(newSecuredMessage("Tarjeta de crédito: 1111 1111 1111 1111, DNI: 11111111A",Arrays.asList("(\\d{4} \\d{4} \\d{4} \\d{1})(?=\\d{3})","(\\d{6})(?=\\d{2}[A-Z])")));logger.info("Tarjeta de crédito: 1111 1111 1111 1111, DNI: 11111111A");}}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
packageio.github.picodotdev.blogbitix.log4j;importorg.apache.logging.log4j.message.Message;importjava.util.Collection;importjava.util.regex.Matcher;importjava.util.regex.Pattern;importjava.util.stream.Collectors;publicclassSecuredMessageimplementsMessage{privatestaticfinalintUNMASKED_CHARACTERS=3;privateMessagemessage;privateStringstring;privatePatternpattern;publicSecuredMessage(Messagemessage,Collection<String>patterns){this.message=message;this.pattern=compilePatterns(patterns);}publicSecuredMessage(Stringstring,Collection<String>patterns){this.string=string;this.pattern=compilePatterns(patterns);}...@OverridepublicStringgetFormattedMessage(){returnsecuredMessage();}privateStringsecuredMessage(){if(message!=null){returnsecuredMessage(message);}elseif(string!=null){returnsecuredString(string);}return"";}privatePatterncompilePatterns(Collection<String>patterns){returnPattern.compile(patterns.stream().map(it->"("+it+")").collect(Collectors.joining("|")));}privateStringsecuredMessage(Messagemessage){returnsecuredString(message.getFormattedMessage());}privateStringsecuredString(Stringstring){Stringresult=string;Matchermatcher=pattern.matcher(string);while(matcher.find()){Stringmatch=matcher.group();Stringmask=mask(match);result=result.replaceFirst(match,mask);}returnresult;}privateStringmask(Stringstring){returnstring.replaceAll(".","*");}}

Utilizar una clase que implemente la interfaz Message para realizar el reemplazo requiere modificar todos los puntos de la aplicación que emitan información sensible, para evitar posibles omisiones este aspecto de la aplicación se puede delegar en Log4j y ser aplicado de forma global.

Con los parámetros de configuración replace, regex y replacement el reemplazo los hace la clase PatterLayout utilizando una expresión similar regular que en el caso de SecuredMessage.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
configuration:status:warnappenders:console:name:STDOUTpatternLayout:pattern:"%d{DEFAULT} %X{uuid} %-5level %60.60logger %msg%n"replace:regex:"(\\d{4} \\d{4} \\d{4} \\d{1})(?=\\d{3})|(\\d{6})(?=\\d{2}[A-Z])"replacement:"**********"loggers:root:level:infoappenderRef:ref:STDOUT

En la salida del ejemplo la primera traza corresponde al uso de la clase SecurdMessage y la segunda al PatternLayout.

1
2
3
...
2019-02-10 11:22:47,652 INFO io.github.picodotdev.blogbitix.log4j.Main Tarjeta de crédito: ****************111, DNI: ******11A
2019-02-10 11:22:47,653 INFO io.github.picodotdev.blogbitix.log4j.Main Tarjeta de crédito: **********111, DNI: **********11A

El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub y probarlo en tu equipo ejecutando el comando ./gradlew run.


Viewing all articles
Browse latest Browse all 2721