spring_2기[본캠프]/과제

[과제] Spring 플러스 프로젝트 Day 3

minwoo95 2026. 3. 11. 01:01

https://github.com/TheOne-team-1/TheOne-Bottle-Shop

 

GitHub - TheOne-team-1/TheOne-Bottle-Shop: 주류 커머스 플랫폼 백엔드 구현하기

주류 커머스 플랫폼 백엔드 구현하기. Contribute to TheOne-team-1/TheOne-Bottle-Shop development by creating an account on GitHub.

github.com

 

1. [보안 및 성능] Redis 기반 로그인 재시도 제한(Rate Limiting)
배경: 무차별 대입 공격(Brute-force)으로부터 사용자 계정을 보호해야 하는 상황.

문제 인식: 단순히 DB에 fail_count 컬럼을 만들면, 공격자가 1초에 수백 번 로그인을 시도할 때마다 DB 쓰기(Write) 작업이 발생하여 성능 저하와 커넥션 고갈을 초래함.

잠금 해제 로직(예: 30초 후 해제)을 위해 스케줄러를 돌리는 것은 추가적인 서버 자원을 낭비함.

기술적 해결:

In-Memory DB(Redis)를 도입하여 로그인 실패 횟수를 관리. 메모리 기반이라 입출력 속도가 매우 빠르고 메인 DB에 부하를 주지 않음.

Redis의 TTL(Time To Live) 기능을 활용하여 30초가 지나면 실패 횟수 데이터가 자동으로 삭제되도록 설계. 별도의 '잠금 해제' 로직을 짤 필요 없이 인프라 기능을 이용해 복잡도를 낮춤.

단순 기능 구현을 넘어, 시스템 부하 분산과 자동화된 리소스 관리를 최우선으로 고려

2. [API 설계] IDOR 취약점 방어와 RESTful한 상태 변경
배경: 사용자의 배송지 주소를 수정하고 삭제하는 기능 개발.

문제 인식: PATCH /api/address/10 요청 시, 서버가 주소 10번이 요청자의 것인지 확인하지 않는다면 타인이 내 주소를 조작할 수 있는 보안 허점(IDOR)이 발생함.

삭제 시 데이터를 완전히 지우면, 나중에 사용자가 "내 주소가 왜 없어졌죠?"라고 문의했을 때 CS 대응이 불가능해짐.

기술적 해결:

Authorization 강화: JWT에서 추출한 memberId와 DB에서 조회한 주소의 ownerId를 대조하는 로직을 인터셉터나 서비스 계층에 배치. 일치하지 않으면 즉시 403 Forbidden을 반환하여 접근 차단.

Soft Delete 도입: deleted_at 컬럼을 활용해 논리적으로 삭제 처리. 데이터의 이력은 남기되, 일반적인 조회 쿼리에서는 제외되도록 처리하여 데이터 복구 가능성과 무결성을 동시에 확보.

데이터의 소유권 검증을 통해 보안을 강화하고, 비즈니스 연속성을 위해 논리 삭제 방식을 채택

3. [데이터 무결성] 동시성 이슈를 고려한 DB 제약 조건 설계
배경: 상품 리뷰 시스템에서 '1개 주문 상세당 1개의 리뷰'만 허용해야 함.

문제 인식: 동일한 주문 상세(order_detail_id)로 짧은 찰나에 두 번의 요청이 들어올 경우(Race Condition), 자바 로직(if (exists))만으로는 두 요청 모두 검증을 통과하여 중복 데이터가 들어갈 수 있음.

기술적 해결:

DB Unique Constraint: 테이블 설계 단계에서 order_detail_id에 Unique 제약 조건을 설정.

어플리케이션이 실수를 하더라도 데이터베이스 엔진 수준에서 중복 입력을 원천 차단하는 이중 방어막(Defense in Depth) 구축.

코드의 동시성 이슈를 인지하고, 데이터의 정합성을 보장하기 위한 최종 방어선으로 DB 제약 조건을 적극 활용

4. [협업 및 아키텍처] Enum 기반의 공통 예외 응답 처리
배경: 프로젝트 규모가 커짐에 따라 다양한 에러가 발생하고 응답 형식이 파편화됨.

문제 인식: 어떤 API는 String으로 에러를 주고, 어떤 API는 JSON 객체로 주면 프론트엔드에서 공통적인 에러 핸들링이 불가능함. 이는 디버깅 속도를 늦추고 협업 비용을 증가시킴.

기술적 해결:

Custom Exception & Enum: 에러 코드와 메시지를 MemberExceptionEnum으로 관리하여 비즈니스 의미를 명확히 함.

Global Exception Handler: @RestControllerAdvice를 사용해 모든 예외가 정해진 JSON 규격(success, status, message, data)으로만 나가도록 단일 통로를 구축.

협업의 효율성을 높이기 위해 API 응답 구조를 표준화하고, 예외 처리의 일관성을 확보