오늘날의 데이터 중심 세계에서는 데이터 보안이 가장 중요합니다. 로깅 프레임워크는 애플리케이션 모니터링 및 디버깅에서 중요한 역할을 하지만 노출되어서는 안 되는 민감한 정보를 실수로 노출할 수 있습니다. 로그 마스킹은 로그 메시지의 민감한 데이터를 효과적으로 난독화하여 기밀 정보를 보호하는 기술입니다.
Logback은 Java 애플리케이션에서 강력하고 주로 사용되는 로깅 프레임워크입니다. 로그 이벤트를 JSON 개체로 형식화하는 기능을 포함하여 유연한 구성 옵션을 제공합니다. Log4j 프레임워크의 후속 버전으로, 기능과 사용 용이성으로 인해 빠르게 인기를 얻었습니다. Logger, Encoders, Layout, Appender, Encoder로 구성되어 있습니다.
로거: 로거는 로그 메시지의 컨텍스트입니다. 애플리케이션은 이 클래스와 상호 작용하여 로그 메시지를 생성합니다.
인코더: 인코더는 로그백 0.9.91에 도입되었으며 이벤트를 바이트 배열로 변환하고 해당 바이트 배열을 OutputStream에 쓰는 역할을 담당합니다. 레이아웃으로 도입된 인코더는 이벤트를 비바이너리 출력으로 범위를 제한하는 문자열로만 변환할 수 있습니다.
레이아웃: 레이아웃은 사용자가 원하는 대로 로깅 요청의 형식을 지정하는 역할을 하는 반면, 어펜더는 형식이 지정된 출력을 대상으로 보내는 작업을 담당합니다.
어펜더: 로그백에서 출력 대상을 어펜더라고 합니다. 이렇게 하면 로그 메시지가 최종 목적지에 배치됩니다. Logger에는 둘 이상의 Appender가 있을 수 있습니다. 현재 콘솔, 파일, 원격 소켓 서버, MySQL, PostgreSQL, Oracle 및 기타 데이터베이스, JMS 및 원격 UNIX Syslog 데몬에 대한 어펜더가 존재합니다.
logstash-logback-encoder 라이브러리는 Spring Boot 애플리케이션의 로깅 기능을 향상시키는 데 유용한 도구입니다. 구조화된 JSON 형식으로 로그 메시지의 형식을 지정하는 편리한 방법을 제공하므로 Logstash와 같은 로그 집계 및 분석 도구를 통해 쉽게 사용할 수 있습니다. JSON 형식은 구조화되고 기계가 읽을 수 있는 로그 정보 방식을 제공하므로 고급 로그 분석 및 보안 조치에 이상적입니다. Logstash의 장점
JSON 사용자 정의 Logstash를 사용하면 특정 필드와 메타데이터를 포함하도록 JSON 출력을 사용자 정의할 수 있습니다.
동적 필드 또한 애플리케이션 컨텍스트에 따라 로그 이벤트에 필드를 동적으로 추가할 수 있습니다.
향상된 가독성 JSON 형식은 로그 이벤트에 대해 명확하고 사람이 읽을 수 있는 구조를 제공합니다.
향상된 검색 및 분석 로그 집계 도구를 사용하면 JSON 로그를 쉽게 구문 분석하고 쿼리할 수 있습니다.
기계 분석 JSON 로그는 자동화된 분석 및 경고 시스템에 이상적입니다.
여기서 주요 목표는 런타임 시 사용자 정의 및 구성이 가능한 데이터를 마스킹하는 솔루션을 제공하는 것입니다.
다음은
에 대한 간단한 요구 사항입니다.1단계
스프링 부트 애플리케이션을 생성합니다. 이 솔루션은 사용자 정의가 거의 필요하지 않은 모든 Java 기반 애플리케이션에서 작동합니다.
2단계
데이터를 마스킹하도록 모든 정규식을 구성합니다. 정규식은 리소스 활용 측면에서 비용이 많이 든다는 점을 기억하세요. 정규식을 조정하고 있는지 확인하세요. Regex 그룹을 사용하면 문자열에서 필수 하위 문자열을 선택할 수 있습니다.
3단계
클래스를 만들고 MessageJsonProvider를 구현합니다. 이 인터페이스는 logstash에서 왔으며 어펜더로 인쇄하기 전에 메시지를 사용자 정의할 수 있게 해줍니다. 이 인터페이스의 writeTo 메소드는 모든 로그 메시지에 대해 호출됩니다.
start() 메소드에서 모든 정규식을 읽고 모든 MaskingRule을 포함하는 LogMasker를 준비합니다. 이 메서드는 AbstractJsonProvider에서 가져온 것이며 단순히 시작된 프로세스를 true로 표시합니다.
MaskingRule은 정규식 패턴과 함수를 보유합니다. 이 함수는 로그에서 식별된 문자열을 대체합니다.
@Data public class MaskingMessagingProvider extends MessageJsonProvider { public static final String DEFAULT_RULES_DELIMITER = ","; private LogMasker logMasker; private String rules; public MaskingMessagingProvider() { super(); } @Override public void start() { super.start(); this.logMasker = LogMasker.create(StringUtils.tokenizeToStringArray(rules, DEFAULT_RULES_DELIMITER)); } @Override public void writeTo(JsonGenerator generator, ILoggingEvent event) throws IOException { if (isStarted()) { JsonWritingUtils.writeStringField(generator, getFieldName(), logMasker.mask(event.getFormattedMessage())); } } } class LogMasker { private MaskingRule[] masks; public LogMasker(MaskingRule[] masks) { super(); this.masks = masks.clone(); } public static LogMasker create(String[] rules) { return new LogMasker(Arrays.stream(rules).map(rule -> MaskingRule.create(rule)).toArray(MaskingRule[]::new)); } public String mask(String input) { String transformed = input; for (MaskingRule m : masks) { transformed = m.mask(transformed); } return transformed; } } class MaskingRule { public static final int REG_EX_DEFAULT_GROUP_SELECTOR = 2; public static final String DEFAULT_REPLACEMENT = "*"; private Pattern pattern; private UnaryOperator<String> replacement; public MaskingRule(Pattern maskPattern, UnaryOperator<String> replacement) { super(); this.pattern = maskPattern; this.replacement = replacement; } public static MaskingRule create(String rule) { return new MaskingRule(Pattern.compile(rule), (in) -> MaskingRule.maskDataWithReplacement(in, DEFAULT_REPLACEMENT)); } public String mask(String transformed) { Matcher matcher = pattern.matcher(transformed); StringBuffer sb = new StringBuffer(); while (matcher.find()) { matcher.appendReplacement(sb, replacement.apply(getDataToBeMasked(matcher))); } matcher.appendTail(sb); return sb.toString(); } private static String maskDataWithReplacement(String input, String replacement) { int repetition = !StringUtils.hasLength(input) ? 0 : input.length(); return String.join("", Collections.nCopies(repetition, replacement)); } private static String getDataToBeMasked(Matcher matcher) { if (matcher.groupCount() > 1) { return matcher.group(REG_EX_DEFAULT_GROUP_SELECTOR); } return matcher.groupCount() > 0 ? matcher.group(1) : ""; } }
4단계
logback-spring.xml 파일에 클래스를 구성합니다.
<configuration> <springProperty scope="context" name="rules" source="app.logging.masking.rules" defaultValue=""/> <appender name="CONSOLE"> <p><strong>Steps 5</strong><br> Run the application. For simplicity, i have taken a string which is holding data and printing it at application start up.<br> </p> <pre class="brush:php;toolbar:false">@SpringBootApplication @Slf4j public class LogDataMaskingApplication { public static void main(String[] args) { SpringApplication.run(LogDataMaskingApplication.class, args); LogDataMaskingApplication.maskingTest(); } public static void maskingTest() { String data = "{\"loginName\":\"maskingtest\",\"phoneNumber\":\"9898981212\",\"password\":\"Masking@123\"}"; log.info(data); } }
이것은 매우 기본적인 솔루션이며 메시지 다이제스트 등과 같은 요구 사항에 따라 개선할 여지가 많습니다...
GitHub에서 코드를 찾을 수 있습니다.
궁금하신 점은 댓글 남겨주세요
위 내용은 정규식을 사용하여 Java에서 logstash 로그백으로 로그 마스크의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!