rollingfile pattern example ejemplo java encryption log4j

java - example - log4j2 pattern



Proteger/Encriptar archivos log4j (3)

Tengo un problema ; requisito de seguridad tengo la aplicación java swing que tiene archivos de registro generados con log4j para problemas de soporte en caso de seguimiento de un error.

Tengo que codificar / cifrar / asegurar los archivos para que el cliente no pueda abrirlos y verlos (al menos no de forma legible) y, al mismo tiempo, cuando el equipo técnico de soporte tome estos archivos, sabrán cómo leerlos ( descifrarlos ). .

Hice muchas búsquedas y probé mi mejor opción que encontré, que es construir un appender personalizado extendiendo SkeletonAppender .

Ahora sé que tengo log4j funcionando muy bien como la configuración de abajo, pero creé una nueva clase para cifrarlo, pero no puedo hacer que funcione, incluso con una configuración simple, no crear el archivo, así que puedo continuar en la parte de cifrado.

Cualquier ayuda, los enlaces son buenos.

Trabajando ... versión

<appender name="cache" class="com.MyAppender"> <param name="Threshold" value="ALL" /> <param name="ImmediateFlush" value="true" /> <param name="File" value="${home}/logs/cache.log"/> <param name="Append" value="true"/> <param name="Threshold" value="ALL" /> <param name="Encoding" value="UTF-8" /> <layout class="org.apache.log4j.EnhancedPatternLayout"> <param name="ConversionPattern" value="%-5p %d{MMM-dd-yyyy HH:mm:ss,SSS} %c{1} - %m%n" /> </layout> </appender>

No funciona ... versión

<appender name="cache" class="com.MyAppender"> <param name="Threshold" value="ALL" /> <param name="ImmediateFlush" value="true" /> <param name="File" value="${home}/logs/cache.log"/> <param name="Append" value="true"/> <param name="Threshold" value="ALL" /> <param name="Encoding" value="UTF-8" /> <rollingPolicy class="org.apache.log4j.rolling.TimeBasedRollingPolicy"> <param name="FileNamePattern" value="${home}/logs/cache.%d{yyyy-MM-dd-HH}.gz" /> <param name="ActiveFileName" value="${home}/logs/cache.log" /> </rollingPolicy> <layout class="org.apache.log4j.EnhancedPatternLayout"> <param name="ConversionPattern" value="%-5p %d{MMM-dd-yyyy HH:mm:ss,SSS} %c{1} - %m%n" /> </layout> </appender>

La prueba de clase simple

http://www.javaworld.com/article/2075817/core-java/customized-appender-extending-org-apache-log4j-fileappender.html

package com.MyAppender; import org.apache.log4j.spi.LoggingEvent; public class MyAppender extends org.apache.log4j.RollingFileAppender { private String file; private boolean initialized = false; private String baseFileName = null; // private static final Log log = LogFactory.getLog(MyAppender.class); /** * * write to ActivityLog * * @param event * logging event invoked. * */ @Override protected void subAppend(LoggingEvent event) { if (!initialized) { createNewFile(); } synchronized (this) { super.subAppend(event); } } /** * * create a new ActivityLog File * */ public void createNewFile() { try { baseFileName = file; super.setFile(baseFileName); super.activateOptions(); initialized = true; } catch (Exception e) { // log.error("*#*Error in configuration of log4j params,unable to create ActivityLog file"); } } /** * * invokes File Appender''s activateOptions() which controls the creation of * log files. * */ @Override public void activateOptions() { super.setFile(file); super.activateOptions(); } /** * * Close and rename the current ActivityLog file and reset counter and * timestamp. * */ public void rollOver() { closeFile(); initialized = false; } @Override public void setFile(String file) { this.file = file; } }

Luego planeo implementar el código en Cipher OutputStream


Opción 1: usar un SocketAppender personalizado

Como alternativa a la respuesta de Zim-Zam sobre el uso de un appender compatible con JDBC (recuerde que también debe habilitar el transporte seguro, por cierto, si va por esta ruta), también puede utilizar un SocketAppender y desplegar su propio cifrado. método.

Opción 2: usar Flume y un FlumeAppender

Consulte la here y eche un vistazo al uso de FlumeAppender , que admite el cifrado de eventos:

Una configuración de muestra de FlumeAppender que está configurada con un agente primario y un agente secundario, comprime el cuerpo, formatea el cuerpo con el RFC5424Layout y persiste los eventos cifrados en el disco. Esta muestra "comprime el cuerpo, formatea el cuerpo utilizando el RFC5424Layout y persiste los eventos cifrados en el disco:"

<?xml version="1.0" encoding="UTF-8"?> <Configuration status="warn" name="MyApp" packages=""> <Appenders> <Flume name="eventLogger" compress="true" type="persistent" dataDir="./logData"> <Agent host="192.168.10.101" port="8800"/> <RFC5424Layout enterpriseNumber="18060" includeMDC="true" appName="MyApp"/> <Property name="keyProvider">MySecretProvider</Property> </Flume> </Appenders> <Loggers> <Root level="error"> <AppenderRef ref="eventLogger"/> </Root> </Loggers> </Configuration>

Lecturas interesantes

Esto no responde directamente a su pregunta, pero también es bastante interesante: Crear un archivo de registro cifrado


Creo que estás buscando algo como esto. Aunque no sugeriré usarlo. Si está enviando la clave con el código, hay muchos de-compiladores para descompilar archivos jar / class y obtener la "clave". De lo contrario deberías usar PKI y todo ..? No he visto esa opción aquí.

extender la clase RollingFileAppender

public class EncryptedRollingFileAppender extends RollingFileAppender

ya que la clase RollingFileAppender no es la clase final, así que puedes hacerlo.

método de sobrescritura

public synchronized void setFile(String fileName, boolean append, boolean bufferedIO, int bufferSize) throws IOException

algo como esto.

LogLog.debug("setFile called: " + fileName + ", " + append); // It does not make sense to have immediate flush and bufferedIO. if (bufferedIO) { setImmediateFlush(false); } reset(); OutputStream ostream = null; try { // // attempt to create file // // ostream = new FileOutputStream(fileName, append); ostream = this.createEncryptedOutputStream(fileName, append); } catch (FileNotFoundException ex) { // // if parent directory does not exist then // attempt to create it and try to create file // see bug 9150 // String parentName = new File(fileName).getParent(); if (parentName != null) { File parentDir = new File(parentName); if (!parentDir.exists() && parentDir.mkdirs()) { // ostream = new FileOutputStream(fileName, append); try { ostream = this.createEncryptedOutputStream(fileName, append); } catch (Exception e) { e.printStackTrace(); } } else { throw ex; } } else { throw ex; } } catch (Exception e) { throw new FileNotFoundException(); } Writer fw = createWriter(ostream); if (bufferedIO) { fw = new BufferedWriter(fw, bufferSize); } this.setQWForFiles(fw); this.fileName = fileName; this.fileAppend = append; this.bufferedIO = bufferedIO; this.bufferSize = bufferSize; writeHeader(); LogLog.debug("setFile ended"); if (append) { File f = new File(fileName); ((CountingQuietWriter) qw).setCount(f.length()); }

la mayor parte del código se copia de la clase base.

El método privado de encriptación debe verse algo como esto

private OutputStream createEncryptedOutputStream(String filename, boolean append) throws FileNotFoundException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException { CipherOutputStream cstream = null; try { byte[] keyBytes = "1234123412341234".getBytes(); //example final byte[] ivBytes = new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f }; //example final SecretKey key = new SecretKeySpec(keyBytes, "AES"); final IvParameterSpec IV = new IvParameterSpec(ivBytes); final Cipher cipher = Cipher.getInstance("AES/CFB8/NoPadding"); cipher.init(Cipher.ENCRYPT_MODE, key, IV); cstream = new CipherOutputStream(new FileOutputStream(filename, append), cipher); } catch (FileNotFoundException e) { throw e; } return (cstream); }

No perderá ninguna capacidad de RollingFileAppender. Puedes hacer una codificación similar en otros usuarios también.

Descargo de responsabilidad: - Por favor, no estas claves @ producción, si lo está utilizando. Una vez más, estás enviando llaves con tu tarro. Un pirata informático inteligente puede piratear cosas fácilmente. Se debe hacer una gran cantidad de código ya que se trata de un "registro". No he probado este código.


Una posible solución al problema es escribir los registros en una base de datos integrada que admita el cifrado. Por ejemplo, H2 admite de forma nativa el cifrado y SQLite tiene extensiones de cifrado de código abierto. De esta manera, solo puede usar el JDBCAppender y dejar que la base de datos se encargue del cifrado sin tener que preocuparse por un appender personalizado.

De esta pregunta , la configuración de SQLite se vería algo así como

<appender name="jdbcAppender" class="org.apache.log4j.jdbc.JDBCAppender"> <param name="URL" value="jdbc:sqlite:D:/download/mapLogic/sf_log.db" /> <param name="user" value="" /> <param name="password" value="" /> <param name="driver" value="org.sqlite.JDBC" /> <param name="sql" value="INSERT INTO Log(Message,Priority,Logger,Date) VALUES (''%m'',''%p'',''%c'',''%d{ABSOLUTE}'')" /> </appender>

donde se ve tu tabla de registro

CREATE TABLE Log ( LogId INTEGER PRIMARY KEY, Date DATETIME NOT NULL, Level VARCHAR(50) NOT NULL, Logger VARCHAR(255) NOT NULL, Message TEXT DEFAULT NULL );

La documentación sobre el JDBCAppender se puede encontrar here

Hay una extensión de cifrado official para SQLite, así como al menos una extensión de código abierto de terceros; Nunca he tenido que cifrar SQLite, pero si tuviera que hacerlo, utilizaría la extensión oficial a menos que tuviera problemas con ella.

Si está ejecutando esto en el cliente, lo ideal es que tenga el teléfono del programa en casa al momento del inicio para obtener la clave de cifrado de la base de datos para que la clave nunca exista en la unidad de disco del cliente (ignorando la posibilidad de que vaya para el archivo de intercambio): el cliente todavía podría usar un depurador o lo que sea para tratar de sacar la clave de la memoria, pero presumiblemente no está lo suficientemente interesado en descifrar los registros para ir a esa cantidad de problemas. Si tiene que almacenar la clave en el lado del cliente, entonces puede, como mínimo, ofuscarla con el hashing varias veces antes de usarla, por ejemplo, codifique la clave base_ del programa y luego, al momento del arranque, cree la clave real al ejecutar base_key. a través de SHA512 (o lo que sea) varias veces; el cliente aún podría descubrir qué estás haciendo usando un depurador, pero de nuevo con suerte no querrán meterse en problemas.