[java] SLF4J와 Log4j2의 추가 로그 파일 암호화
보안은 모든 소프트웨어 시스템에서 매우 중요한 요소입니다. 특히 로그 파일에는 보호해야 할 중요한 정보가 포함될 수 있습니다. SLF4J와 Log4j2를 사용하여 암호화 된 로그 파일을 생성하는 방법을 알아보겠습니다.
1. 의존성 추가
먼저, 프로젝트의 Maven 또는 Gradle 빌드 파일에 SLF4J와 Log4j2의 의존성을 추가해야 합니다. 다음은 Maven을 사용하는 경우의 예시입니다:
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.32</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.14.1</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.14.1</version>
</dependency>
</dependencies>
2. 암호화된 로그 파일 구성
Log4j2는 XML 또는 프로그래밍 방식으로 로그 파일 구성을 설정할 수 있습니다. 암호화된 로그 파일을 생성하기 위해 프로그래밍 방식으로 설정하는 방법을 소개하겠습니다.
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.core.config.Configuration;
import org.apache.logging.log4j.core.config.ConfigurationFactory;
import org.apache.logging.log4j.core.config.ConfigurationSource;
import org.apache.logging.log4j.core.config.Configurator;
import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
import org.apache.logging.log4j.core.config.plugins.util.PluginBuilderAttribute;
import org.apache.logging.log4j.core.config.plugins.util.PluginBuilderFactory;
import org.apache.logging.log4j.core.util.Builder;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.io.Serializable;
import java.util.Base64;
public class EncryptedFileAppenderConfigFactory extends ConfigurationFactory {
@Override
protected String[] getSupportedTypes() {
return new String[]{"*"};
}
@Override
public Configuration getConfiguration(ConfigurationSource source) {
return getConfiguration(source, null);
}
@Override
public Configuration getConfiguration(ConfigurationSource source, ClassLoader loader) {
return new EncryptedFileAppenderConfig(source);
}
private static class EncryptedFileAppenderConfig extends ConfigurationBuilder<BuiltConfiguration> implements Serializable {
private static final long serialVersionUID = 1L;
static {
ConfigurationBuilderFactory.addBuilder("EncryptedFileAppender", new BuilderFactory());
}
private EncryptedFileAppenderConfig(ConfigurationSource source) {
super.setConfigurationSource(source);
}
private static class Builder extends AbstractConfigurationBuilder<Builder> implements org.apache.logging.log4j.core.util.Builder<BuiltConfiguration> {
private String key;
private String algorithm;
@Override
public BuiltConfiguration build() {
try {
byte[] decodedKey = Base64.getDecoder().decode(key);
SecretKeySpec secretKey = new SecretKeySpec(decodedKey, algorithm);
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
add(encryptedFileAppender("EncryptedFile", "log/encrypted.log", getCipheredLayout(cipher)));
setLogger(levels(Level.INFO).add(newAppenderRef("EncryptedFile")).attribute("additivity", false));
return build(true);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
@PluginBuilderAttribute("key")
public Builder setKey(String key) {
this.key = key;
return this;
}
@PluginBuilderAttribute("algorithm")
public Builder setAlgorithm(String algorithm) {
this.algorithm = algorithm;
return this;
}
}
private static class BuilderFactory implements org.apache.logging.log4j.core.config.plugins.util.Builder<Builder> {
@Override
public Builder build() {
return new Builder();
}
}
}
private static org.apache.logging.log4j.core.layout.PatternLayout getCipheredLayout(Cipher cipher) {
return org.apache.logging.log4j.core.layout.PatternLayout.newBuilder()
.withPattern("%d [%t] %-5level %logger{36} - %msg%n")
.withCharset("UTF-8")
.withConfiguration(configuration)
.withFilter(new EncryptedFilter(cipher))
.build();
}
private static org.apache.logging.log4j.core.appender.EncryptingFileAppender.Builder encryptedFileAppender(String name, String fileName, org.apache.logging.log4j.core.layout.PatternLayout layout) {
return org.apache.logging.log4j.core.appender.EncryptingFileAppender.newBuilder()
.withName(name)
.withFileName(fileName)
.withImmediateFlush(true)
.withLayout(layout);
}
private static org.apache.logging.log4j.core.Filter levels(Level level) {
return org.apache.logging.log4j.core.filter.LevelRangeFilter.createFilter(level, Level.ALL, true, false);
}
private static class EncryptedFilter implements org.apache.logging.log4j.core.Filter {
private final Cipher cipher;
public EncryptedFilter(Cipher cipher) {
this.cipher = cipher;
}
@Override
public Result filter(LogEvent event) {
try {
String message = event.getMessage().getFormattedMessage();
byte[] encryptedMessage = cipher.doFinal(message.getBytes());
String encodedMessage = Base64.getEncoder().encodeToString(encryptedMessage);
LogEvent newEvent = new Log4jLogEvent.Builder()
.setLoggerName(event.getLoggerName())
.setLoggerFqcn(event.getLoggerFqcn())
.setLevel(event.getLevel())
.setMessage(new SimpleMessage(encodedMessage))
.setTimeMillis(event.getTimeMillis())
.build();
return Result.ACCEPT_AND_PROCEED;
} catch (Exception e) {
e.printStackTrace();
return Result.NEUTRAL;
}
}
}
}
3. 로그 파일 암호화 설정
Log4j2 XML 구성 파일에서 다음과 같이 새로 작성한 Factory 클래스를 사용하여 로그 파일 암호화를 설정할 수 있습니다.
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="INFO">
<Appenders>
<EncryptedFileAppender name="EncryptedFileAppender" key="YOUR_ENCRYPTION_KEY" algorithm="AES">
<PatternLayout pattern="%d [%t] %-5level %logger{36} - %msg%n"/>
</EncryptedFileAppender>
</Appenders>
<Loggers>
<Root level="info">
<AppenderRef ref="EncryptedFileAppender"/>
</Root>
</Loggers>
</Configuration>
주의: YOUR_ENCRYPTION_KEY
를 원하는 실제 암호화 키로 교체해야 합니다.
암호화된 로그 파일 설정이 완료되었습니다! 이제 프로그램을 실행하면 로그 파일이 암호화되어 생성됩니다.