【问题标题】:Secure / Encrypt log4j files保护/加密 log4j 文件
【发布时间】:2015-05-13 13:14:32
【问题描述】:

我有问题; security 要求我有 java swing 应用程序,该应用程序具有使用 log4j 生成的日志文件,以便在跟踪时出现支持问题 一个错误。

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

我做了很多搜索,并尝试了我发现的最佳选择,即通过扩展 SkeletonAppender 来构建自定义附加程序。

现在知道我的 log4j 工作正常继续加密部分。

任何帮助,链接都很好。

工作...版本

<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

【问题讨论】:

  • 我使用了javaworld.com/article/2075817/core-java/… 中的代码并且它可以工作,但是在log4j.xml 中没有rollingPolicy 标签如何包含它*我将更新我的代码*
  • 与其乱用 appender,不如考虑对写入日志的数据进行加密,而不是对日志本身进​​行加密。换句话说,对日志中的所有内容进行加密至关重要,或者是否可以只加密敏感数据而将非敏感数据(例如时间戳等)保留为纯文本?
  • 谢谢@Bohemian 好主意,但看看stackoverflow.com/questions/629755/… 它有安全漏洞你还有其他好主意吗
  • 我忘了说它的 SWING appliaciotn
  • 我认为你应该实现一个Encoder,用你的CypherOutputStream装饰OutputStreamlogback.qos.ch/manual/encoders.html

标签: java encryption log4j


【解决方案1】:

解决此问题的一种可能方法是将日志写入支持加密的嵌入式数据库,例如H2 原生支持加密,SQLite 具有开源加密扩展 - 这样您就可以使用 JDBCAppender 并让数据库负责加密,而无需担心自定义附加程序。


来自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,然后在启动时通过SHA512(或其他)运行base_key几次来创建actual_key;客户仍然可以通过使用调试器来弄清楚您在做什么,但他们希望再次不想麻烦。

【讨论】:

  • 感谢您的建议,但我忘了提及它的 SWING 应用程序
  • 我认为它不适用于我的 java swing 应用程序,我不想添加数据库只是为了加密......或者我应该在客户端机器上添加 sql lite,因为我真的很关心性能.
  • @shareef 使用embedded database,您通常可以处理主机应用程序中的所有操作 - 您不需要安装单独的数据库服务器,即使用加密的嵌入式数据库是合适/可行的在客户的机器上。 (例如,Firefox 使用嵌入式 SQLite 来管理 cookie/历史记录/等 - 它不需要使用单独的 SQLite 服务器来执行此操作。)
  • 您知道,如果您通过一些链接增强答案,那么带有嵌入式 sql 的 jdbc 看起来会很有帮助。优化答案,以便其他人也可以使用,我会接受答案,谢谢
  • @shareef 我已经扩展了我的答案
【解决方案2】:

选项 1:使用自定义 SocketAppender

作为 Zim-Zam 关于使用支持 JDBC 的附加程序的答案的替代方案(顺便说一句,如果您沿着这条路线走,请记住启用安全传输),您还可以考虑使用 SocketAppender 和推出您自己的加密方法。

选项 2:使用 Flume 和 FlumeAppender

参考log4j documentation on appenders,看看使用FlumeAppender,它支持事件加密:

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

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

有趣的阅读

这并不能直接回答你的问题,但也很有趣:Creating an encrypted log file

【讨论】:

    【解决方案3】:

    我认为你看起来像这样。虽然我不建议使用它。如果您随代码一起提供密钥,则有很多反编译器可以反编译 jar/类文件并获取“密钥”。否则你应该使用 PKI 和所有..?我没有在这里研究这个选项。

    扩展 RollingFileAppender 类

    public class EncryptedRollingFileAppender extends RollingFileAppender
    

    因为 RollingFileAppender 类不是 final 类所以你可以这样做。

    覆盖方法

    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 的任何功能。您也可以在其他附加程序中进行类似的编码。

    免责声明:- 如果您正在使用这些密钥,请不要在生产环境中使用。同样,您将随罐子一起运送钥匙。一个聪明的黑客可以轻松地破解东西。因为它是“记录”,所以要对代码进行微调。我没有测试过这段代码。

    【讨论】:

      猜你喜欢
      • 2010-09-22
      • 2011-10-24
      • 1970-01-01
      • 1970-01-01
      • 2014-12-16
      • 2012-01-21
      • 2010-11-08
      • 2018-05-15
      相关资源
      最近更新 更多