You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[ Infra ] #80 머지 전 운영 전제 확인 (XFF 신뢰, 리프레시 토큰 저장소) #90
이 이슈의 항목들은 인프라 사실 확인이라 애플리케이션이 알 수 없습니다. 그중 둘은 코드 쪽에서 다룰 수 있었습니다.
2번 (리프레시 토큰 저장소) — 막았습니다
운영 프로파일 기본값은 이미 redis 였지만 JWT_REFRESH_TOKEN_STORE 로 덮을 수 있습니다. 기본값에 기대지 않고prod 에서 NoopRefreshTokenStore 가 선택되면 기동을 막습니다.
none 이면 로그아웃이 200 을 돌려주면서 아무것도 폐기하지 못합니다. 조용히 틀린 상태라 운영에서 알아차릴 방법이 없어서, "뜨지 않는 편이 낫다" 로 판단했습니다.
1번 (XFF 신뢰) — 사후 확인 수단을 만들었습니다
보안그룹은 코드 밖이지만, 전제가 깨졌는지는 런타임에 알 수 있습니다. XFF 를 신뢰하도록 설정했다는 건 "프록시 뒤에 있다" 는 전제인데, XFF 없는 요청이 오면 그 요청은 프록시를 거치지 않았습니다.
carecode.ratelimit.unproxied.requests
0 이 아니면 8082 가 외부에 열려 있다는 뜻입니다. 배포 후 이 값으로 첫 체크박스를 확인할 수 있습니다. (루프백은 세지 않습니다 — 배포 헬스체크가 그 경로입니다.)
3번 (인증 메일 기준 주소) — 이미 되어 있습니다
EMAIL_VERIFICATION_BASE_URL 미설정 시 기동이 실패합니다(의도된 fail-fast). 배포 검증 단계에서 걸리므로 운영은 무사합니다.
남은 것 — 서버를 봐야 합니다
항목
확인 방법
8082 가 Nginx 에서만 접근 가능한가
보안그룹 인바운드 규칙. 배포 후 위 지표로 사후 확인
Nginx 가 XFF 를 덮어쓰는가
proxy_set_header X-Forwarded-For $remote_addr 여야 안전합니다. $proxy_add_x_forwarded_for 면 클라이언트 값이 앞에 붙어 위조값이 첫 항목이 됩니다 — 그 설정이면 RATE_LIMIT_TRUST_XFF=false 로 두는 쪽이 낫습니다
Redis 영속성(AOF/RDB)
끄면 재시작 시 전체 세션이 끊깁니다. 감수할지 결정 필요
세 번째 항목의 "마지막 To Do"(배포 후 X-RateLimit-* 가 클라이언트별로 다르게 나오는지 실측)는 배포가 시작된 뒤에야 가능합니다 — #94 의 시크릿이 전제입니다.
Activity
RosieOh commentedon Aug 22, 2026
리뷰 결과 — 항목 1(XFF)의 전제가 틀렸다
머지 전 점검 중 확인한 내용이다. 이 이슈에 처음 적은 근거가 사실과 달랐다.
실질적인 XFF 신뢰 스위치는
app.rate-limit.*이 아니다application.yml에 이미 있는 설정이 진짜 스위치다.이게 등록하는
ForwardedHeaderFilter가 요청을 감싸서getRemoteAddr()자체를X-Forwarded-For 의 클라이언트 주소로 바꿔친다. 실측 결과다.
ClientIpResolver는trust=false일 때getRemoteAddr()로 폴백하는데,그 값이 이미 헤더에서 온 것이라 두 설정이 같은 결과를 낸다.
ForwardedClientIpTest로 고정해 뒀다.그래서 달라지는 것
이 앱에서는 성립하지 않는다.
forward-headers-strategy가 켜져 있는 한 클라이언트별로 구분된다.#80이전부터 이미 존재했고,#80의RATE_LIMIT_TRUST_XFF=true는 새로 만든 위험이 아니다.#80머지를 막지 않는다. 다만 아래 확인은 여전히 필요하다.남은 확인 (머지와 무관하게 유효)
배포가 포트를 모든 인터페이스에 바인딩한다.
즉 보안그룹/방화벽이 유일한 방어선이고, 뚫려 있으면 XFF 위조로 IP 기준 제한
(로그인 시도, 인증코드 발송)이 무력화된다. 이건
#80과 독립적인 기존 리스크다.-p 127.0.0.1:$PORT:8082로 바인딩을 좁히는 것을 검토X-Forwarded-For를 덮어쓰는지(proxy_set_header X-Forwarded-For $remote_addr)확인 — 이어붙이면(
$proxy_add_x_forwarded_for) 첫 항목이 클라이언트 위조값이 될 수 있다app.rate-limit.trust-forwarded-headers를 없애고forward-headers-strategy하나로 일원화할지 검토 (지금은 이름이 통제력을 과장한다)항목 3 (인증 메일 기준 주소) — 기동 실패로 변경
#80에서 운영 기본값을 빈 문자열로 뒀는데, 그러면 링크가/auth/verify?token=...상대 경로로 나가 메일에서 클릭이 안 된다. 사용자는 이유를 모른 채 인증에 실패한다.
기본값을 제거해
DB_PASSWORD/JWT_SECRET과 같은 취급으로 바꿨다.환경변수가 없으면 기동이 실패한다.
배포 실패는 헬스체크에서 걸리고 블루/그린 전환이 안 되므로 자동 롤백된다 — 안전한 실패다.
/opt/carecode/.env에EMAIL_VERIFICATION_BASE_URL추가 (다음 배포 전 필수)항목 2 (리프레시 토큰 저장소) — 변경 없음
redis유지. rate limit 인터셉터가 이미 모든 요청에서 Redis 를 쓰므로 Redis 는사실상 기존 필수 의존이고, 새 의존을 추가하는 것이 아니다.
RosieOh commentedon Oct 23, 2026
코드로 막을 수 있는 둘을 처리했습니다 (#154)
이 이슈의 항목들은 인프라 사실 확인이라 애플리케이션이 알 수 없습니다. 그중 둘은 코드 쪽에서 다룰 수 있었습니다.
2번 (리프레시 토큰 저장소) — 막았습니다
운영 프로파일 기본값은 이미
redis였지만JWT_REFRESH_TOKEN_STORE로 덮을 수 있습니다. 기본값에 기대지 않고prod에서NoopRefreshTokenStore가 선택되면 기동을 막습니다.none이면 로그아웃이 200 을 돌려주면서 아무것도 폐기하지 못합니다. 조용히 틀린 상태라 운영에서 알아차릴 방법이 없어서, "뜨지 않는 편이 낫다" 로 판단했습니다.1번 (XFF 신뢰) — 사후 확인 수단을 만들었습니다
보안그룹은 코드 밖이지만, 전제가 깨졌는지는 런타임에 알 수 있습니다. XFF 를 신뢰하도록 설정했다는 건 "프록시 뒤에 있다" 는 전제인데, XFF 없는 요청이 오면 그 요청은 프록시를 거치지 않았습니다.
0 이 아니면 8082 가 외부에 열려 있다는 뜻입니다. 배포 후 이 값으로 첫 체크박스를 확인할 수 있습니다. (루프백은 세지 않습니다 — 배포 헬스체크가 그 경로입니다.)
3번 (인증 메일 기준 주소) — 이미 되어 있습니다
EMAIL_VERIFICATION_BASE_URL미설정 시 기동이 실패합니다(의도된 fail-fast). 배포 검증 단계에서 걸리므로 운영은 무사합니다.남은 것 — 서버를 봐야 합니다
proxy_set_header X-Forwarded-For $remote_addr여야 안전합니다.$proxy_add_x_forwarded_for면 클라이언트 값이 앞에 붙어 위조값이 첫 항목이 됩니다 — 그 설정이면RATE_LIMIT_TRUST_XFF=false로 두는 쪽이 낫습니다세 번째 항목의 "마지막 To Do"(배포 후
X-RateLimit-*가 클라이언트별로 다르게 나오는지 실측)는 배포가 시작된 뒤에야 가능합니다 — #94 의 시크릿이 전제입니다.