결제 연동 보안 체크리스트 — 키 하드코딩·콜백 검증
결제 사고라고 하면 카드 번호가 우리 서버에 쌓이는 장면만 떠올리기 쉽습니다. 실제 중소 자사몰·앱 커머스에서는 더 흔한 유형이 있습니다. 비밀 키 유출, 가짜 성공 통지를 그대로 믿기, 화면에서 금액을 조작하기, 테스트와 운영 환경을 섞는 일입니다.
이들은 오픈 직후에도 조용히 쌓이다가 정산·환불·고객 분쟁으로 드러납니다. 이 글은 특정 결제사 콘솔 조작법이나 비밀 값을 다루지 않습니다. 외주 검수나 자체 점검 때 바로 쓸 수 있는 실무 안내에 가깝습니다.

절대 하지 말 것: 키를 코드에 박기
결제에 쓰는 “키”에는 여러 종류가 있습니다. 화면에 노출해도 되는 값과, 절대 밖으로 나가면 안 되는 비밀 값이 섞여 있습니다.
- 클라이언트용 키 / 시크릿 키
- 웹훅(서버 간 통지) 검증용 비밀
- 상점 아이디와 짝이 되는 인증 정보
- 내부 중계 서버용 API 키
코드 저장소, 전 직원 PC, 퇴사자 노트북, 스크린샷, 로그 수집기까지 복제 경로는 많습니다. 앱이나 웹 파일 묶음에 시크릿을 넣으면 추출이 더 쉽습니다.
시크릿은 서버 쪽 설정·비밀 저장소에만 두고, 배포 과정에서 주입하는 편이 안전합니다. 깃 이력에 한 번 들어간 키는 유출된 것으로 보고 재발급하는 것이 좋습니다.
환경은 처음부터 나눕니다
| 환경 | 사용 키 | 통지 받을 주소 | 실결제 |
|---|---|---|---|
| 로컬·개발 | 테스트 키 | 개발 도메인 | 불가·모의 |
| 스테이징 | 테스트 또는 제한 키 | 시험 도메인 | 정책에 따름 |
| 운영 | 라이브 키 | 운영 도메인만 | 실결제 |
테스트 키로 운영 오픈하기, 라이브 키를 메신저에 붙여 넣기, 운영 통지를 개인 임시 주소로 받기 같은 일은 모두 사고 유형입니다.
금액과 주문은 서버가 최종 결정
결제창에 넘기는 금액·주문번호를 브라우저나 앱이 최종 확정하면 조작 위험이 큽니다.
권장 흐름은 개념적으로 이렇습니다.
- 서버가 주문과 결제 예정 금액을 만들고 고정한다.
- 클라이언트는 그 주문에 대한 결제만 시작한다.
- 승인 후 서버가 결제사에 승인 조회·확정을 한다.
- 응답의 금액·주문번호가 내부 기록과 일치할 때만 결제완료로 바꾼다.
“결제 성공 화면 HTML”만 보고 주문을 바꾸면, 위조 페이지나 중간 조작에 취약합니다.
돌아옴(리다이렉트)과 서버 통지(웹훅)
사용자가 결제 후 쇼핑몰로 돌아오는 경로와, 결제사 서버가 쇼핑몰 서버로 결과를 보내는 경로는 다릅니다.
- 리다이렉트
사용자 화면이 돌아오며 성공·실패를 보여 줌. 중간에 앱을 종료할 수 있음 - 웹훅
결제사 서버가 결과를 보냄. 나중에 다시 보내질 수 있음
둘 중 하나만 믿으면 주문이 영원히 “결제중”이거나, 반대로 미결제인데 “결제완료”가 됩니다.
통지를 받을 때는 최소한 아래를 확인합니다.
- 우리 서버의 허용 경로와 안전한 통신으로만 들어오는가
- 서명·검증 절차를 통과한 요청만 처리하는가
- 같은 결제 결과가 두 번 와도 한 번만 반영하는가
- 금액·주문번호가 내부 기록과 맞는가
- 검증 실패 시 성공 처리하지 않고 기록·알림을 남기는가
서명 검증 없이 “성공이라는 글자만 있으면 OK”는 위조 통지에 그대로 열립니다.
카드 번호를 우리가 받을 필요는 거의 없습니다
중소 자사몰이 카드 번호를 직접 입력받아 저장할 이유는 거의 없습니다. 결제창·토큰화·결제사 호스팅 방식을 쓰면 카드 원문 저장 부담을 크게 줄일 수 있습니다.
특수한 이유로 민감 결제 데이터를 다룬다면 범위와 인증 요구가 달라집니다. 개발 전에 결제사·보안 전문가와 범위를 따로 잡는 것이 맞습니다. 이 글은 그 범위를 대체하지 않습니다.
로그·관리자·앱에서도 새 구멍이 납니다
해킹만이 아니라 내부 도구에서도 사고가 납니다.
- 로그에 시크릿·카드 전체·주민번호·접속 토큰을 남기지 말 것
- 관리자 수동 환불·금액 수정은 역할 제한과 감사 기록을 둘 것
- 운영 DB를 손으로 고쳐서 결제완료 처리하지 말 것
- 퇴사자·외주 종료 시 키 재발급과 계정 회수를 할 것
앱·WebView에서는 외부 결제 앱에서 돌아온 직후, 서버 확정 전에 성공 화면을 확정하지 않는 것이 좋습니다. 딥링크로 결제완료를 위조하지 못하게 하고, 디버그 빌드에 라이브 키가 들어가지 않게 빌드를 나눕니다.
오픈 전 최소 시나리오
- 정상 결제 → 주문 결제완료, 재고 차감, 같은 통지 두 번은 한 번만 반영
- 결제 중 앱 종료 → 통지·조회로 최종 상태 회복
- 금액이 안 맞는 응답 → 주문 미확정, 알림
- 부분 취소·전액 취소 → 결제사·주문·재고 일치
- 테스트 키 환경에서 라이브 주소 호출이 막히는지
이렇게 준비하면 좋아요
- □ 시크릿 키가 저장소·앱 파일에 없는지 검색한다
- □ 테스트·라이브 키와 통지 주소가 환경별로 나뉘었는지 확인한다
- □ 결제 금액·주문이 서버에서 고정되는지 본다
- □ 승인 확정이 서버와 결제사 검증을 거치는지 확인한다
- □ 웹훅 서명 검증과 중복 반영 방지가 있는지 묻는다
- □ 리다이렉트만으로 결제완료 처리하지 않는지 시연한다
- □ 로그에 민감 정보가 없는지 샘플을 본다
- □ 관리자 환불·강제 상태 변경 권한을 정한다
- □ 키 재발급·계정 회수 절차를 한 장으로 남긴다
키 유출은 재발급으로 끝나지 않을 수 있습니다. 위조 승인을 믿으면 재고·배송·정산이 한꺼번에 더러워집니다. “일단 붙이고 보안은 나중에”는 결제 영역에서 특히 비싼 문장입니다.
이 글은 실무 보안 점검 안내용이며, 법률 자문을 대신하지 않습니다. 규제 준수·사고 대응은 법률·보안 전문가와 확인하세요.
LB Contents는 쇼핑몰·앱 결제 연동 시 키 관리, 콜백 검증, 주문 확정, 운영 권한을 포함한 구조로 설계합니다. 오픈 전 결제 보안 점검이 필요하면 상담할 수 있습니다.