자동화 slecs

결제 웹훅 발신자 위조 공격 차단 강화

목차

결제 플랫폼에서 들어오는 웹훅의 발신자 IP를 검증하는 방식을 개선했다. XFF(X-Forwarded-For) 헤더를 다룰 때 보안 취약점이 있었는데, 맨 뒤 값(위조 불가능한 IP)을 사용하도록 변경한 작업이다.

웹훅 IP 검증이 중요한 이유

결제 플랫폼의 웹훅은 결제 완료, 취소, 환불 같은 중요한 이벤트를 우리 서버로 전달한다. 이 이벤트들은 직접 데이터베이스를 변경하고 비즈니스 로직을 실행하므로, 정당한 발신처임을 확인하는 것이 매우 중요하다.

일반적으로 웹훅 보안은 다층 방어로 구성된다:
- 서명(Signature) 검증: 결제 플랫폼이 제공하는 서명이 유효한지 확인
- IP 화이트리스트: 알려진 결제 플랫폼 IP에서만 요청 수용
- 타임스탬프 검증: 요청 생성 시간이 너무 오래되지 않았는지 확인
- HTTPS 채널: 암호화된 통신

이 중 IP 검증은 네트워크 레벨에서 동작하므로 비교적 빠르고 효과적이다. 하지만 현대의 클라우드 환경에서는 로드밸런서, 리버스 프록시, CDN 등을 거치면서 클라이언트의 실제 IP가 변조될 수 있다.

X-Forwarded-For 헤더의 함정

로드밸런서나 리버스 프록시를 거친 요청에서는 XFF 헤더로 원본 클라이언트의 IP를 추적한다. 하지만 이 헤더는 각 레이어를 거칠 때마다 값이 쌓인다:

X-Forwarded-For: 203.0.113.10, 198.51.100.20, 192.0.2.30
                 └─ 클라이언트      └─ 프록시1      └─ 로드밸런서

여기서 결정해야 할 근본적인 문제가 생긴다: 어느 IP를 신뢰할 것인가?

접근 방식 설명 보안도 문제점
첫 번째 값 203.0.113.10 클라이언트가 임의로 조작 가능
마지막 값 192.0.2.30 ⭐⭐⭐ 로드밸런서가 추가하므로 신뢰 가능
특정 인덱스 임의의 위치 ⭐⭐ 프록시 구조 변경 시 깨짐

왜 맨 뒤 값인가?

로드밸런서나 리버스 프록시는 클라이언트를 보는 마지막 지점이다. 요청이 프록시를 통과할 때, 프록시는 자신에게 직접 연결된 IP를 알고 있고, 이 정보를 XFF 헤더의 맨 뒤에 추가한다.

따라서 맨 뒤 IP는 우리 인프라 경계의 가장 바깥쪽에서 기록된 값이므로, 네트워크 외부에서 위조가 불가능하다. 물론 우리 인프라 내부에서 조작할 수도 있지만, 그건 이미 내부 보안 영역의 문제이므로 다른 차원이다.

// 개선 전: 신뢰할 수 없는 IP 값 사용
String clientIp = request.getHeader("X-Forwarded-For").split(",")[0];

// 개선 후: XFF 헤더의 마지막(맨 뒤) 값 사용
String[] ips = request.getHeader("X-Forwarded-For").split(",");
String trustedClientIp = ips[ips.length - 1].trim();

변경 사항과 영향

Java 기반 결제 모듈의 웹훅 검증 로직을 수정했다. 이전에는 일관성 없게 여러 방식으로 클라이언트 IP를 추출했을 가능성이 높고, 이를 XFF 헤더의 마지막 값으로 통일했다.

실제 개선의 핵심:
- 결제 플랫폼의 IP 화이트리스트와 요청의 맨 뒤 IP를 비교
- 일치하면 허용, 불일치하면 차단
- 이 로직으로 위조된 IP를 가진 악의적 웹훅 요청은 자동으로 차단됨
- 정당한 요청은 로드밸런서가 추가한 신뢰할 수 있는 IP로만 도착하므로 정상 통과

팀이 배운 점과 일반론

1. 보안은 "빠르게 지나가기"보다 "결정하기"
XFF 헤더를 "그냥 사용하면 되지" 하고 넘어갈 수 있지만, 어느 값을 신뢰할 것인가는 중요한 보안 결정이다. 이런 작은 결정들이 모여 시스템의 견고함을 결정한다. 코드 리뷰할 때도 "이 IP는 어디서 온 거고, 신뢰할 수 있나?"를 질문하는 습관이 중요하다.

2. 결제 시스템은 "여러 검증"이 필수
일반적인 API 엔드포인트는 한두 가지 검증으로 괜찮을 수 있지만, 결제 관련 처리는 서명, IP, 타임스탐프 등을 모두 검증하는 다층 방어가 필수다. 한 가지만 뚫리더라도 시스템이 동작하도록.

3. 외부 API 연동할 때의 체크리스트
- 상대방이 제공하는 서명 검증 구현됐나?
- 신뢰할 수 있는 IP 목록을 어디서 얻을 것인가?
- 우리 인프라의 프록시 구조를 이해하고 있나?
- 실제 프로덕션 환경에서 웹훅이 정상 도착하는지 테스트했나?
- 만약 발신처가 IP를 변경하면 어떻게 업데이트할 것인가?

4. 역으로 생각하기
우리가 다른 서비스에 웹훅을 보낼 때도 같은 방식으로 상대방의 검증이 구성될 것이다. 상대방이 우리의 IP를 확인할 때, 우리도 NAT, 프록시, 로드밸런서를 고려한 IP 설정이 필요할 수 있다는 뜻이다. 때로는 상대방에게 "이 IP 범위에서 나가요"라고 미리 알려주는 게 필요하다.

이런 변경들은 사용자 입장에서는 눈에 띄지 않지만, 결제 안정성과 보안에 실질적으로 기여한다.


🛒 이 글과 어울리는 추천 상품

*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.

댓글 0

첫 댓글 달아줘.