TIL

TIL - 결제 금액 조작문제 서버측 이중검증으로 방어하기

kinim329 2026. 3. 11. 23:07

1. 배경

배달 앱 '수라간' 프로젝트에서 결제 도메인을 담당하며 외부 PG사(토스페이먼츠) API를 연동했다. 단순히 API를 호출하고 승인 결과를 받는 것에 그치지 않고, 실제 운영 환경에서 발생할 수 있는 보안 취약점을 고민하던 중 **'금액 변조'**의 위험성을 발견했다.

 

2. 핵심 이슈: "클라이언트의 데이터는 언제든 조작될 수 있다"

결제 프로세스는 브라우저(Client)에서 시작된다. 사용자가 주문 페이지에서 결제 버튼을 누를 때, 브라우저의 개발자 도구를 사용하면 PG사로 넘겨주는 결제 금액을 임의로 수정할 수 있다.

  • 위험 상황: 10,000원짜리 음식을 주문하면서, 브라우저 단에서 금액을 100원으로 조작해 승인 요청을 보내는 경우.
  • 문제점: 서버에서 별도의 검증 로직이 없다면, 시스템은 100원이 결제된 것을 성공으로 인지하고 주문을 처리하게 된다. 이는 서비스의 금전적 손실과 직결되는 심각한 보안 결함이다.

3. 해결 방법: 서버 사이드 '이중 검증(Cross-Check)' 로직 구현

클라이언트에서 넘어오는 데이터는 '신뢰할 수 없는 데이터'로 간주하고, 우리 시스템이 가진 '원천 데이터(Source of Truth)'와 대조하는 과정을 추가했다.

  1. 사용자로부터 결제 승인 요청(OrderId, Amount 등)을 받는다.
  2. 외부 API를 호출하기 전, DB에서 해당 OrderId의 실제 주문 금액을 조회한다.
  3. DB의 주문 금액과 클라이언트가 보낸 요청 금액을 1원 단위까지 비교한다.
  4. 데이터가 일치할 때만 외부 API 승인 절차를 진행하며, 불일치 시 즉시 예외를 발생시키고 결제를 차단한다.

4. 깨달은 점: '방어적 설계(Defensive Design)'의 중요성

모든 데이터 검증의 책임은 결국 서버에 있다는 것을 다시 한번 체득했다.

  • 데이터 무결성: 단순히 기능을 구현하는 것을 넘어, 시스템 간 데이터가 오가는 접점에서 발생할 수 있는 예외 상황을 설계 단계에서 차단하는 것이 얼마나 중요한지 배웠다.
  • 보안의 기본: "클라이언트의 입력값은 절대 신뢰하지 않는다"라는 보안의 기본 원칙을 결제 도메인에 적용해 보며, 엔지니어로서 가져야 할 비판적 사고의 필요성을 느꼈다.