결제 플랫폼 보안 취약점 9건 한꺼번에 잡은 후기
목차
코드 리뷰 한 방에 9건
결제 플랫폼 코드 리뷰 받은 거 한꺼번에 정리함. CRITICAL 2건, HIGH 4건, MEDIUM 3건. 충전/이체/파트너 관리/API 키 인증 구간이 골고루 걸렸음. 생각보다 한 군데 몰려 있어서 작업 자체는 반나절 컷.
| 등급 | 영역 | 핵심 |
|---|---|---|
| CRITICAL | 이체 | 금액 검증 누락 + 동시성 |
| CRITICAL | API 키 인증 | 평문 비교 |
| HIGH | 충전 | 중복 요청 처리 |
| HIGH | 파트너 조회 | 권한 우회 |
| MEDIUM | 공통 | 로깅에 민감정보 노출 |
CRITICAL 두 건이 제일 아팠음
이체 쪽은 음수 금액·0원이 그대로 통과되는 케이스가 있었음. 프론트에서 막고 있다고 안심했던 건데, 외부에서 직접 호출이 들어오면 그대로 트랜잭션이 깔리는 구조였음. 진입점에서 다시 막아야 한다는 걸 또 까먹은 거였음.
if (amount == null || amount.signum() <= 0) {
throw new IllegalArgumentException("amount must be positive");
}
API 키 쪽은 더 부끄러움. 그냥 equals 로 비교하고 있었음. 길이 다르면 빨리 빠져나오는 패턴이라 타이밍 공격 여지가 있다고 지적받음. 상수시간 비교로 바꿔서 정리함.
- 검증은 진입 레이어에서 한 번 + 도메인에서 한 번, 두 겹으로
- 비밀값 비교는 무조건 상수시간 비교 함수
- 동시성은 DB 레벨 락으로, 애플리케이션 락으로 잡으려고 하지 말 것
HIGH/MEDIUM 정리
충전 중복 요청은 멱등키를 받아두고 처리 결과를 캐싱하는 식으로 풀었음. 같은 요청을 두 번 누르는 사용자가 생각보다 많아서, 토스트 띄워도 그새 두 번 들어오는 케이스가 잡힘.
파트너 조회는 전형적인 IDOR 비슷한 거였음. 파라미터로 받은 파트너 식별자를 그대로 신뢰하면 안 되는데, 세션 컨텍스트에 들어 있는 파트너 식별자랑 일치하는지 한 번 더 확인하도록 고침.
- MEDIUM 로깅 이슈는 카드 뒷자리·전화번호가 평문으로 찍히던 구간 마스킹
- 마스킹 유틸을 따로 빼서 다른 진입 레이어도 같이 정리
- 권한 체크 헬퍼 하나로 통일해서 누락 방지
회고
리뷰 받기 전엔 "이 정도는 이미 다 막아뒀지" 라고 생각했는데 막상 받아 보니 9건. 특히 검증 누락은 진입점이 늘어날수록 계속 새는 부분이라, 차라리 공통 검증기를 따로 하나 두는 게 낫겠다는 생각. 동시성도 트래픽이 더 늘기 전에 한 번 정리해 두는 게 안전해 보임. 다음 리뷰 들어가기 전까지 그 두 가지 먼저 손보는 걸로.
끝
댓글 0
첫 댓글 달아줘.