安全/加密log4j文件

时间:2015-05-13 13:14:33

标签: java encryption log4j

我有问题; 安全性要求我有java swing应用程序,其中包含使用 log4j 生成的日志文件,以便在跟踪时获得支持问题 一个错误。

我必须 ecrypt / cypher / secure文件,以便客户端无法打开它们并查看它们(至少不是人类可读的方式),同时支持技术团队获取这些文件他们会知道如何阅读(解密)。

我做了很多搜索,我尝试了我发现的最佳选项,即通过扩展SkeletonAppender构建自定义appender。

现在知道我有 log4j 工作得很好,如下面的配置,但我创建了新的类来加密它但我不能让它工作,即使简单的设置它不会创建文件,所以我可以继续在ecnryption部分。

任何帮助,链接都很好。

...工作版本

<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>

不工作......版本

   <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>

简单的班级考试

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;
    }

}

然后我打算在中实现代码 Cipher OutputStream

3 个答案:

答案 0 :(得分:8)

该问题的可能解决方法是将日志写入支持加密的嵌入式数据库,例如: H2原生支持加密,SQLite具有开源加密扩展 - 这样您就可以使用JDBCAppender并让数据库负责加密,而不必担心自定义appender。< / p>

this question开始,SQLite配置看起来像

<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>

您的日志表如何

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
);

可以找到JDBCAppender上的文档here

SQLite以及official第三方开源扩展程序有at least one加密扩展名;我从来没有对SQLite进行过加密,但如果我必须这样做,那么除非我遇到问题,否则我会使用官方扩展。

如果您在客户端上运行此操作,那么理想情况下,您将能够在启动时将程序电话置于家中以获取数据库加密密钥,以便密钥永远不会存在于客户端的磁盘驱动器上(忽略该可能性)它转到交换文件) - 客户端仍然可以使用调试器或其他任何东西来尝试从内存中获取密钥,但可能他们对解密日志没有足够的兴趣来解决这个问题。如果你必须在客户端存储密钥,那么在使用它之前,你至少可以通过对它进行几次散列来对其进行混淆,例如:对程序中的base_key进行硬编码,然后在启动时通过多次运行base_key到SHA512(或其他)来创建actual_key;客户端仍然可以通过使用调试器来确定您正在做什么,但他们希望他们再也不希望遇到麻烦。

答案 1 :(得分:6)

选项1:使用Custom SocketAppender

作为Zim-Zam关于使用支持JDBC的appender的回答的替代方法(记住也要启用安全传输,顺便说一下,如果沿着这条路线走),你也可以考虑使用{{1}并推出自己的加密方法。

选项2:使用Flume和FlumeAppender

请参阅log4j documentation on appenders并查看使用支持事件加密的SocketAppender

使用主代理和辅助代理配置的FlumeAppender配置示例,压缩主体,使用RFC5424Layout格式化主体,并将加密事件持久保存到磁盘。此示例“压缩正文,使用RFC5424Layout格式化正文,并将加密事件持久保存到磁盘:”

FlumeAppender

有趣的阅读

这不会直接回答您的问题,但也非常有趣:Creating an encrypted log file

答案 2 :(得分:0)

我认为你看起来像这样。虽然我不建议使用它。如果您使用代码发送密钥,那么有很多反编译器可以反编译jar / class文件并获得&#34; key&#34;。否则你应该使用PKI和所有..?我在这里没有考虑过这个选项。

扩展RollingFileAppender类

public class EncryptedRollingFileAppender extends RollingFileAppender
由于RollingFileAppender类不是最终类,所以你可以这样做。

覆盖方法

public synchronized void setFile(String fileName, boolean append,
        boolean bufferedIO, int bufferSize) throws IOException
像这样的东西。

        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());
    }

大多数代码都是从基类复制的。

加密私有方法应该看起来像这样

    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);
}

你不会失去RollingFileAppender的任何功能。您也可以对其他appender进行类似的编码。

免责声明: - 如果您正在使用,请不要使用这些密钥@ production。再次,你用罐子装运钥匙。一个聪明的黑客可以轻松地破解事物。因为它是“记录”而需要完成的代码调整。我还没有测试过这段代码。