보안 재구축 제안 · 설계 데모 포함

상품권 판매 시스템
보안 재구축 제안서

침입 경로를 막고, 그래도 지켜야 할 것은 따로 지키겠습니다

신영진  |  풀스택 개발 · 시스템 운영

가장 중요한 요구부터 설계했습니다

"침입이 발생하더라도 상품권 번호가 노출되지 않는 구조" — 이것은 방화벽이 아니라 설계로 푸는 문제입니다

상품권 번호 보호
1등록 즉시 암호화관리자가 번호를 입력하면 바로 암호화해 저장합니다. DB에 평문이 존재하지 않습니다
2키를 분리 보관복호화 키를 DB·웹서버와 다른 곳에 둡니다. DB를 통째로 가져가도 번호를 풀 수 없습니다
3조회 시 재인증관리자 화면에서도 기본은 가려진 상태. 확인하려면 OTP를 다시 거칩니다
4조회 이력 기록누가 언제 어떤 번호를 열었는지 남습니다. 대량 조회가 발생하면 바로 확인됩니다
관리자 계정이 탈취된 경우까지 가정합니다 — 이전 사고가 관리자 화면 경로였다는 점을 고려했습니다. 관리자라고 해서 번호를 한눈에 볼 수 있으면, 관리자 계정 하나가 뚫리는 순간 전량이 유출됩니다.
02

결제 금액 조작과 권한 우회

두 가지 모두 화면이 아니라 서버에서 막습니다

결제 금액 검증

결제 금액 검증

화면에서 넘어온 금액을 믿지 않고 서버가 주문 구성을 다시 조회해 계산합니다. 불일치하면 승인 자체를 시도하지 않고, 승인 후에도 PG 승인 금액과 한 번 더 대조합니다

회원 등급 권한

회원 등급별 권한

버튼을 숨기는 방식은 주소를 직접 입력하면 뚫립니다. 모든 요청에서 서버가 등급을 다시 확인하고 권한이 없으면 데이터를 돌려주지 않습니다

카드·휴대폰 100만원 한도와 통신사 수수료는 관리자에서 설정값으로 관리하고, 검증은 서버에서 수행합니다. 설정을 코드에 고정하지 않아야 운영 중 조정이 가능합니다.
03

실제 공격을 막아본 경험

롯데카드 마이데이터 운영 중 현금성 리워드 이벤트에 대한 반복 어뷰징 공격에 대응했습니다

1어떤 공격이었나공격자들이 조건을 우회해 같은 보상을 반복해서 받아가는 시도가 지속됐습니다. 요청을 자동화해 짧은 시간에 대량으로 보내거나, 정상 흐름을 건너뛰고 지급 요청만 직접 호출하는 방식이었습니다
2화면에서 막는 건 소용없다버튼을 숨기거나 횟수를 제한해도 요청을 직접 흉내 내면 그대로 통과합니다. 검증은 전부 서버에서 해야 한다는 것을 그때 확인했습니다
3한 번만 처리되는 구조같은 요청이 여러 번 들어와도 결과가 한 번만 반영되도록 해야 합니다. 이것이 없으면 재시도만으로 중복 지급이 발생합니다
4흐름과 기록이전 단계를 건너뛴 요청은 서버가 거부하고, 어떤 계정이 어떤 순서로 요청했는지 남겨 반복 시도를 찾아냈습니다
이번 프로젝트와 같은 성격입니다 — 결제 금액 조작도 공격자가 돈이 되는 지점을 찾아 반복 시도하고, 화면 단의 제한은 우회하는 구조입니다. 그래서 금액을 서버가 다시 계산하고, 중복 요청을 차단하고, 시도 자체를 기록으로 남기는 방식으로 설계했습니다.

모의해킹을 전문 업무로 수행한 실적은 없습니다. 제 경험은 공격을 실제로 받는 서비스를 운영하며 막아온 쪽입니다.
04

기존 소스 활용 vs 신규 구축

신규 구축을 권합니다. 다만 전부 버리자는 뜻은 아닙니다

보안 점검
1확신할 수 없습니다침해가 있었던 소스는 눈에 보이는 파일을 지워도, 정상 파일 안에 한 줄 삽입된 코드까지 전부 찾았다고 장담하기 어렵습니다
2불확실성이 남습니다그 상태로 운영하면 같은 사고가 반복될 때 원인을 가려내지 못합니다. 새 코드 문제인지 남은 흔적인지 알 수 없습니다
3가져갈 것은 가져갑니다현재 사이트가 기능 명세 역할을 그대로 합니다. 회원·주문 데이터는 검증 후 이관합니다
4규모가 작습니다상품 5종에 기능이 단순해 신규 구축 부담이 크지 않습니다. 대형 쇼핑몰이라면 판단이 달랐을 것입니다
비용 차이 — 기존 소스 보완은 진단과 흔적 제거에 시간이 들고, 그 작업이 끝나도 불확실성이 남습니다. 신규 구축과 비용 차이가 크지 않으면서 결과는 더 확실합니다. 다만 진단 결과에 따라 달라질 수 있어, 착수 초기에 기존 소스를 점검한 뒤 확정하는 것을 제안드립니다.
05

기술 스택 제안

개발 인력이 없으시다고 하여 쉬운 표현으로 정리했습니다

영역제안이유
사용자·관리자Java (Spring Boot)현재 사용자 화면이 이미 Java라 연속성이 있고, PHP를 지양하신다는 조건에도 맞습니다. SQL 인젝션을 구조적으로 막는 방식이 기본으로 제공되며, 이후 유지보수할 개발자를 구하기도 쉽습니다
데이터베이스MySQL 또는 PostgreSQL현재 구성에 맞춰 선택합니다. 상품권 번호는 DB 기능이 아닌 애플리케이션에서 암호화해 저장하므로, DB 자체가 유출돼도 복호화되지 않습니다
서버 구성쇼핑몰·관리자 분리요구하신 대로 도메인과 서버를 분리합니다. 쇼핑몰이 뚫려도 관리자로 넘어가지 않으며, 관리자는 접근 IP 제한 + OTP를 추가합니다
파일 업로드웹 루트 밖 저장업로드 파일을 웹에서 직접 실행할 수 없는 경로에 두고 실행 권한을 제거합니다. 파일이 올라가도 실행되지 않습니다
SSL자동 갱신 구성만료로 인한 접속 장애를 방지합니다
웹 에디터에 대해 — 이전 사고의 경로였던 만큼, 공개 웹 에디터를 그대로 쓰지 않는 것을 제안드립니다. 팝업 등록에 필요한 기능이 서식 있는 글 작성 정도라면, 파일 업로드 기능이 없는 가벼운 구성으로 대체할 수 있습니다. 편집 기능이 꼭 필요하다면 업로드 경로와 실행 권한을 분리한 상태에서만 사용합니다.
06

결제 4종 연동

계좌·카드·휴대폰·토스 간편계좌를 각각 다르게 다뤄야 합니다

1계좌결제한도 없음. 상품별로 관리자 승인 후 구매와 즉시 구매를 구분하고 알림톡을 발송합니다. 입금 알림을 받아 주문과 자동 대조하되, 입금자명과 금액이 모두 일치할 때만 자동 승인하고 나머지는 관리자 확인으로 넘깁니다
2카드 · 휴대폰결제합계 100만원 한도를 서버에서 검증합니다. 휴대폰결제는 통신사 수수료를 관리자 설정값으로 두어 운영 중 조정 가능하게 합니다
3토스 간편계좌즉시 구매는 가능하되 최초 1회 유선 승인 후 번호 확인이 열리는 흐름은 카드·휴대폰과 동일하게 처리합니다
4공통모든 수단에서 서버 기준 금액 검증과 중복 결제 차단을 동일하게 적용합니다. 수단마다 다르게 처리하면 한 곳에 구멍이 생깁니다
결제 연동 경험 — 삼성전자판매 전용몰과 성북구도시관리공단 온라인예약(ezPay)에서 PG 결제 연동을 수행했습니다. 승인 성공 처리보다 승인은 됐는데 서버 기록이 남지 않는 경우, 중복 요청, 취소·환불 같은 예외 처리가 실제 난이도이며 그 부분을 직접 겪으며 다뤄봤습니다.
07

성공적인 마무리의 기준

보안은 "했다"로 끝나지 않고 확인할 수 있어야 한다고 봅니다

1이전 경로가 막힌 것웹쉘 업로드와 SQL 인젝션을 실제로 시도해 차단되는 것을 확인하고 그 결과를 문서로 남기는 것
2번호를 못 여는 것DB를 그대로 내려받아도 상품권 번호가 복호화되지 않는 것. 검수 항목으로 넣으시길 권합니다
3금액을 못 바꾸는 것결제 요청 금액을 임의로 바꿔 보내도 승인되지 않는 것. 4종 모두 확인
4사고 시 추적되는 것번호 조회·권한 변경·관리자 접속 이력이 남아, 문제가 생겼을 때 경로를 되짚을 수 있는 것
무상 하자보수 및 유지보수 — 무상 하자보수 3개월을 제안드립니다. 개발 범위 내 오류 수정과 장애 대응을 포함합니다. 이후 유지보수는 월 단위 협의로, 보안 패치 적용, SSL·서버 관리, 장애 대응, 경미한 수정을 포함합니다. 보안은 한 번 만들고 끝나지 않습니다. 새로운 취약점이 계속 발표되므로 정기적인 점검과 패치가 필요하며, 그 부분을 유지보수에 포함하는 것을 권장드립니다.
08

확인이 필요한 부분

미팅에서 함께 확인하고 싶은 사항입니다

?현재 서버 구성쇼핑몰과 관리자가 같은 서버인지, 분리 시 추가 비용이 어느 정도인지
?이관할 데이터 규모회원 수와 주문 이력 규모. 상품권 번호가 평문으로 저장돼 있다면 이관 시점에 암호화해 옮깁니다
?침해 대응 진행 상황현재 서버가 정리된 상태인지, 사고 시점의 로그가 남아 있는지. 남아 있다면 경로 파악에 도움이 됩니다
?알림톡 발송 채널이미 사용 중인 채널이 있는지. 비밀번호 찾기와 입금 안내에 필요합니다
?결제사 계약 상태4종 각각의 계약이 유지되는지, 재구축 시 재심사가 필요한지
09

막는 것과 지키는 것,
둘 다 하겠습니다

침입 경로를 차단하는 것과, 상품권 번호를 따로 지키는 것은 다른 작업입니다.
둘 다 설계에 담았으며, 데모에서 직접 확인하실 수 있습니다.

신영진  |  풀스택 개발 · 시스템 운영