광고 문의 폼 도배 방어 추가
목차
광고 관련 문의가 늘면서 스팸성 자동 제출이 문제가 되기 시작했다. 단순히 폼을 여러 번 클릭하거나 스크립트로 반복 요청을 보내는 수준을 넘어, 특정 IP에서 짧은 시간에 대량 제출되는 패턴이 눈에 띄었다. 운영자가 처리해야 할 건전하지 않은 요청들이 계속 쌓이고, 정말 필요한 고객 문의를 구분하기 어려워지는 상황이었다. 이번 작업에서는 서버 레벨의 rate limit과 클라이언트 쿨다운을 조합해서 이 문제를 타깃했다.
서버-클라이언트 이중 방어 설계
스팸 방지는 보통 '한 곳에만 하면 된다'는 착각을 하기 쉽다. 하지만 실제로는 양쪽 계층이 다른 목적으로 필요하다.
- 서버 rate limit: 진정성 있는 방어. 클라이언트를 우회하거나 위조한 요청도 막아야 함
- 클라이언트 쿨다운: UX 개선 + 서버 부하 감소. 정상 사용자도 실수로 중복 제출하는 경우를 방지
API 엔드포인트(src/pages/api/ad-inquiry.ts)에서 IP 기반 요청 횟수를 추적하고, 폼 컴포넌트(src/components/AdInquiryWidget.astro)에서 제출 후 일정 시간 동안 다시 제출할 수 없도록 UI를 비활성화하는 방식이다. 이렇게 하면 순간적인 중복 제출은 클라에서, 지속적인 공격성 요청은 서버에서 잡을 수 있다.
IP 기반 Rate Limiting: 세밀한 임계값 설정
이번에 적용한 정책은 다음과 같다:
| 시간 범위 | 제한 건수 | 의도 |
|---|---|---|
| 1시간 | 3건 | 정상 사용자도 문의 폼을 한두 번 재제출할 여유, 즉시적 스팸 차단 |
| 24시간 | 10건 | 하루 동안의 누적 도배 방지 |
이 숫자들은 단순히 임의로 정한 게 아니다. 광고 문의는 보통 한 번만 제출되거나, 오류가 났을 때 최대 한두 번 재제출되는 패턴이다. 따라서 1시간에 3건은 '정상 범위 + 약간의 여유'를 고려한 값이다. 24시간 10건은 같은 IP에서 하루 종일 여러 번 문의를 보내는 정상적인 비즈니스 시나리오(예: 같은 회사의 여러 담당자)를 고려했다. 너무 낮으면 정상 사용자까지 막히고, 너무 높으면 스팸 방지 효과가 없으니까.
클라이언트 쿨다운: 5분의 마찰
폼 컴포넌트에서는 제출 후 5분간 버튼을 비활성화한다. 이 접근법은 몇 가지 이점이 있다:
- 즉각적인 피드백: 사용자가 "아, 방금 제출했으니 다시는 안 된다"는 걸 명확히 알 수 있다
- 서버 부하 감소: 완벽하지 않지만, 의도치 않은 중복 제출의 상당수를 클라에서 걸러낸다
- UX와 보안의 균형: 너무 긴 쿨다운(예: 1시간)은 사용자를 짜증나게 하지만, 5분은 합리적인 선에서 마찰을 준다
실제로 구현할 때는 로컬 스토리지나 메모리에 마지막 제출 시각을 기록하고, 버튼 요소의 disabled 상태와 카운트다운 메시지로 표현했다.
정책 설정과 모니터링의 균형
이런 류의 rate limit을 도입할 때는 처음부터 "완벽한" 정책을 짜려고 애쓰지 않는 게 좋다. 실제 패턴을 관찰하면서 조정하는 게 훨씬 효율적이다. 예를 들어:
- 처음 1주일간 로그를 남겨보니 정상 사용자 중 누군가는 실제로 1시간에 2-3건을 보낸다면, 임계값이 적절한 신호
- 반대로 정상 사용자가 계속 차단된다는 피드백이 들어오면, 1시간 제한을 좀 더 완화해야 할 수도 있다
- 스팸이 여전히 많다면, 추가 필터(이메일 도메인 검증, 폼 필드 값 검증 등)를 고려
현재 설정은 '초기 가설'일 뿐이고, 앞으로 메트릭을 보면서 미세조정하는 게 정상이다.
회고: 스팸 방지의 일반론
이 작업을 하면서 느낀 점들이 몇 가지 있다. 첫째, 계층 분리의 중요성이다. 클라이언트에만 의존하거나 서버에만 의존하면 모두 뚫린다. 둘 다 적절한 수준에서 방어할 때 비로소 견고해진다. 둘째, 임계값 설정은 데이터 기반이어야 한다는 점. 우리 서비스의 정상적인 사용 패턴을 먼저 파악하고 나서 거기에서 조금 벗어난 범위를 정책으로 삼으면 오탐률이 훨씬 낮다. 셋째, 모니터링과 피드백 루프가 없으면 한 번 정책을 정해놓고 계속 문제가 터진다. 정기적으로 차단된 요청 로그를 검토하고, 실제 피드백을 수집해야 한다.
이제 광고 문의 채널이 조금 더 신뢰할 수 있는 상태가 됐다. 운영자들이 정말 필요한 요청에 집중할 수 있게 된 거고, 팀 입장에서는 한 계층의 문제가 확대되는 걸 예방했다.
🛒 이 글과 어울리는 추천 상품
*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.
댓글 0
첫 댓글 달아줘.