728x90
반응형

spring 20

[Spring] 화이트리스트(Whitelist)를 활용한 XSS 공격 철벽 방어하기

XSS란? XSS와 CSRF 개념 및 차이점 정리 XSS와 CSRF 차이점 정리신입 시절, 기술 면접을 준비하거나 보안 관련 문서를 읽을 때마다 항상 헷갈리던 두 단어가 있었습니다.바로 XSS와 CSRF입니다.둘 다 웹 해킹 기법이라는 건 알겠는데, 막상 "정확히 뭐가 달라?"라show5116.tistory.com 웹 애플리케이션을 개발할 때 빼놓을 수 없는 보안 위협 중 하나가 바로 XSS(Cross-Site Scripting)입니다.악의적인 사용자가 웹 페이지에 악성 스크립트를 삽입해 다른 사용자의 정보를 탈취하거나 비정상적인 동작을 유발하는 공격이죠. XSS를 막기 위해 같은 위험한 태그를 막는 블랙리스트(Blacklist) 방식을 종종 사용하지만, 우회 기법이 끊임없이 발전하기 때문에 완벽한 방..

Backend/Spring 2026.04.02

[Spring] P6Spy로 일관된 쿼리 로깅 환경 구축하기

실무에서 프로젝트를 진행하다 보면 JPA만 단독으로 쓰기보다는, 복잡한 통계 쿼리를 위해 QueryDSL을 섞어 쓰거나 레거시 코드로 인해 MyBatis, JdbcTemplate 등을 한 서비스 안에서 혼용하는 경우가 꽤 많죠.저도 이런 환경에서 개발하다 보니, 각 기술마다 쿼리가 찍히는 로깅 포맷이 달라서 디버깅할 때마다 로그 읽기가 너무 고통스럽더라고요.그래서 이 파편화된 로깅 방식을 한 번에 통일해서 잡아주는 P6Spy를 도입하게 되었고, 그 과정과 실무 적용 팁을 공유해 보려고 합니다.1. 왜 P6Spy를 도입해야 할까요?하나의 프로젝트에서 JPA, MyBatis, JdbcTemplate 등을 함께 사용하면 어떤 문제가 발생할까요?JPA(Hibernate): spring.jpa.show-sql=t..

Backend/Spring 2026.03.06

[Spring] 커스텀 어노테이션 4편: Lombok은 어떻게 코드를 만들어낼까? (AST 조작)

어느덧 커스텀 어노테이션 시리즈의 마지막 편입니다!1편의 기본 개념을 시작으로, 2편에서는 런타임에 메소드를 가로채는 AOP를, 3편에서는 클래스 정보를 동적으로 읽어오는 Reflection을 다루었죠. 오늘은 어노테이션 활용의 끝판왕이자, 우리가 숨 쉬듯 사용하고 있는 Lombok(@Getter, @Setter)의 동작 원리인 AST(Abstract Syntax Tree) 조작에 대해 이야기해 보려 합니다. 솔직히 말씀드리면, 4년 차인 저도 실무에서 AST를 직접 조작하는 코드를 구현하지는 않습니다.유지보수도 까다롭고 구현 난이도도 너무 높기 때문이죠.하지만 우리가 매일 쓰는 도구의 원리를 아는 것과 모르는 것은 문제 해결 능력에서 큰 차이를 만듭니다.가벼운 마음으로 "아, 롬복이 이렇게 일하는구나!..

Backend/Spring 2026.03.04

[Spring] 커스텀 어노테이션 3편: 리플렉션(Reflection)으로 메일 폼 자동 생성기 만들기

지난 2편에서는 AOP를 이용해 메소드 앞뒤에 공통 로직을 끼워 넣는 방법을 배웠습니다.하지만 가끔은 메소드 호출을 가로채는 것만으로는 부족할 때가 있습니다."객체 안에 어떤 필드가 있는지 런타임에 다 훑어서, 특정 어노테이션이 붙은 값들만 뽑아낼 수 없을까?" 하는 고민이죠. 저도 실무에서 메일 발송 기능을 구현할 때 비슷한 고민을 했습니다.메일 폼에 들어갈 데이터가 매번 달라지는데, 그때마다 수동으로 Map에 담아주는 게 너무 번거로웠거든요. 오늘은 이 문제를 리플렉션(Reflection)으로 우아하게 해결한 경험을 공유해 드릴게요.1. 리플렉션(Reflection)이란?리플렉션은 구체적인 클래스 타입을 알지 못해도 컴파일된 바이트 코드를 통해 클래스의 메소드, 필드, 어노테이션 정보를 들여다보고 조..

Backend/Spring 2026.03.03

[Spring] 커스텀 어노테이션 2편: AOP로 실행 시간 측정 기능 만들어보기

지난 포스팅에서는 어노테이션의 개념과 동작 원리 3가지를 알아봤습니다.오늘은 그중 실무에서 가장 빈번하게 사용되는 AOP(Aspect Oriented Programming)를 이용해, 우리가 만든 어노테이션에 실제 기능을 불어넣어 보려고 합니다."이 메소드 수행 시간이 얼마나 걸리지?"라는 질문을 받을 때마다 모든 메소드 시작과 끝에 로그를 찍고 계셨나요?이제 @TrackTime 하나로 그 고민을 끝내보겠습니다.1. 왜 AOP인가요?지난 글에서 언급했듯, 어노테이션 자체는 이름표일 뿐입니다.누군가는 이 이름표를 보고 "어? 이거 실행 시간 재야 하네?"라고 판단한 뒤 로직을 끼워 넣어야 하죠.Spring AOP는 타겟 메소드(Target)가 실행될 때 이를 가로채서(Intercept) 앞뒤로 공통 로직을..

Backend/Spring 2026.03.01

[Spring] 커스텀 어노테이션 1편: 어노테이션의 기본 개념과 3가지 동작 원리 이

Spring으로 개발하다 보면 수많은 어노테이션을 만납니다.코드 위에 @ 하나만 붙였을 뿐인데 트랜잭션이 걸리고, JSON으로 변환되는 모습을 보면 가끔은 '마법 같다'는 생각이 들기도 하죠.저도 연차가 쌓이면서 반복되는 로직을 줄이고 싶을 때 "이걸 내가 직접 만들어서 자동화할 순 없을까?"**라는 고민을 하게 되었습니다.오늘부터 시작할 시리즈는 그 마법의 정체를 파악하고, 우리만의 지팡이(커스텀 어노테이션)를 만드는 과정을 담았습니다.그 첫 번째 시간으로 어노테이션의 본질과 이를 동작하게 만드는 3가지 방법에 대해 깊이 있게 다뤄보겠습니다.1. 어노테이션(Annotation)이란 무엇인가?사전적 의미로 어노테이션은 '주석'입니다.하지만 우리가 코드에 쓰는 // 주석과는 결이 다릅니다.일반 주석이 개발..

Backend/Spring 2026.02.27

[Spring] WebClient 동기 처리 시 필수! TCP & Block 이중 타임아웃으로 안정성 확보하기 (RestClient 못 쓸 때)

최근 운영 중인 서비스에서 등에 식은땀이 흐르는 경험을 했습니다.잘 돌아가던 Quartz 스케줄러 Job이 어느 순간부터 로그 하나 없이 '멈춤' 상태가 되어버린 것이죠.에러 로그도 없고, 스레드는 살아있는데 작업이 진행되지 않는 좀비 상태였습니다.원인을 파헤쳐 보니 범인은 WebClient의 block() 메서드였습니다.외부 API 통신 중 예상치 못한 네트워크 이슈가 발생했는데, 타임아웃 설정이 제대로 되어 있지 않아 스레드가 무한 대기 상태에 빠진 것이었죠."WebClient는 비동기인데 왜 block을 써?"라고 하실 수 있지만, 레거시 시스템이나 비즈니스 로직상 반드시 동기 처리가 필요한 경우가 있잖아요?게다가 Spring 버전 문제로 최신 RestClient를 도입할 수도 없는 상황이었습니다...

Backend/Spring 2026.02.12

[Spring Cloud] 장애 전파 막기: Resilience4j 서킷 브레이커 적용

시리즈 첫 글에서 제가 MSA를 선택한 이유로 "리포트 기능이 죽어도 결제는 되어야 한다"는 '장애 격리'를 꼽았던 것, 기억하시나요?하지만 단순히 서비스를 쪼갠다고 해서 저절로 격리가 되는 건 아닙니다. 주문 서비스가 재고 서비스를 호출했는데, 재고 서비스가 응답이 없고 무한 로딩에 걸리면 어떻게 될까요?주문 서비스의 스레드도 응답을 기다리다 다 소진되어, 결국 두 서비스가 같이 죽게 됩니다.오늘은 이 끔찍한 연쇄 장애를 막아주는 두꺼비집, Resilience4j (Circuit Breaker)를 우리 프로젝트에 달아보겠습니다.1. 서킷 브레이커(Circuit Breaker)란?집에 있는 '두꺼비집'을 생각하면 쉽습니다.전기를 너무 많이 쓰거나 누전되면 두꺼비집이 딱! 내려가서 전기를 끊어버리죠? 덕분..

[Java] 가장 효율적인 List 초기화 방법과 상황별 패턴 정리 (불변 vs 가변)

Spring 프로젝트(특히 Spring Security) 코드를 작성하다 보면 다음과 같은 형태의 코드를 자주 마주치게 됩니다.return Collections.singleton(new SimpleGrantedAuthority("ROLE_USER")); "그냥 new ArrayList를 쓰면 되지, 왜 굳이 Collections.singleton을 사용할까?"라는 의문이 드실 수 있습니다.게다가 이 반환값을 받아서 무심코 .add()를 호출했다가는 UnsupportedOperationException이라는 런타임 에러를 만나게 됩니다.오늘은 실무에서 자주 헷갈리는 Java List의 가장 효율적인 초기화 방법들과 '수정 가능(Mutable)' 여부를 명확하게 정리해 드리겠습니다.1. 불변(Immutabl..

Backend/Java 2026.02.02

JPA 대량 데이터 동기화 성능 최적화: Bulk Update

현재 진행 중인 프로젝트에서 'Product(상품)' 데이터를 'Section(규칙)' 정보와 비교하여 동기화(Sync)하는 배치 작업을 구현하고 있었습니다.초기 로직은 단순했습니다.JPA로 Product와 Section 데이터를 모두 조회한다.Java 애플리케이션 메모리 상에서 비교 로직을 수행한다.변경된 데이터는 saveAll(products)로 저장한다.하지만 데이터 양이 늘어나면서 심각한 성능 저하가 발생했습니다.🚨 주요 원인JPA의 N+1 쿼리 발생: saveAll()을 호출해도 내부적으로는 merge()가 동작하면서, 각 엔티티마다 DB에 존재하는지 확인하는 SELECT 쿼리가 발생했습니다. 그 후 UPDATE 쿼리가 건건이 나가는 최악의 상황이었습니다.비효율적인 문자열 파싱: 비교해야 할 ..

Backend/Spring 2026.02.01