새벽 3시에 이메일 알림이 울리기 시작한다. 확인해 보면 의미 없는 영어 광고가 문의 폼을 통해 수십 통 들어와 있다. 소규모 비즈니스 홈페이지를 운영하다 보면 한 번쯤 겪는 일이다. 봇은 어디선가 우리 사이트를 찾아내고, 문의 폼 양식을 자동으로 채워 스팸을 쏟아붓는다.
해결책이라고 reCAPTCHA만 덜컥 붙이면 이번에는 진짜 고객이 '사진 고르는 게 귀찮다'며 폼을 닫는다. 스팸은 막되 UX는 해치지 않는 균형이 필요하다. 실무에서 효과를 확인한 네 가지 장치를 조합별로 소개한다.
1. 허니팟(Honeypot) — 가장 조용한 첫 방어선
허니팟은 사람에게는 보이지 않지만 봇은 채워 넣는 가짜 입력 필드다. 예를 들어 폼에 website라는 숨겨진 input을 하나 추가하고 CSS로 display:none 처리한다. 사람은 못 보니 빈 칸으로 제출되고, 봇은 친절하게 뭔가를 적어서 보낸다. 서버에서 해당 필드에 값이 있으면 그냥 버리면 끝이다.
장점은 사용자 경험에 전혀 영향을 주지 않는다는 것. 단점은 영리한 봇은 이미 허니팟을 우회한다는 점이다. 그래서 이건 단독으로 쓰지 말고 맨 앞단 필터로 생각해야 한다.
2. 시간 기반 검증 — 너무 빨리 제출되면 봇이다
사람이 문의 폼을 채우는 데는 최소 3초 이상 걸린다. 반면 봇은 1초 안에 폼을 읽고 제출한다. 폼이 렌더링된 시각을 hidden 필드에 담아 두고, 제출 시점과 비교해 3초 이내면 차단하는 방식이다. 허니팟과 조합하면 단순 봇의 90% 이상이 걸러진다.
3. reCAPTCHA v3 — 사용자는 모르지만 봇은 걸린다
오래된 reCAPTCHA v2의 '신호등 사진 고르기'는 이탈의 원인이 된다. v3는 사용자 행동을 점수로 환산(0.0~1.0)해 백그라운드에서만 작동한다. 화면에 나타나는 체크박스도, 이미지 선택도 없다. 점수가 0.5 미만이면 백엔드에서 추가 확인을 붙이거나 차단하면 된다.
한국 서비스라면 카카오나 네이버 기반 캡차도 대안이다. 구글 서비스에 제한이 걸리는 기업용 네트워크 환경을 고려한다면 특히 유용하다.
4. 서버 측 레이트 리밋 — 같은 IP의 반복 차단
프론트에서 막아도 결국 HTTP 요청만 직접 쏘는 봇이 남는다. 서버에서 같은 IP는 10분에 3회까지 같은 제한을 거는 게 마지막 방벽이다. Laravel은 throttle 미들웨어, Node.js는 express-rate-limit, Nginx는 limit_req 모듈로 구현할 수 있다. 공용 와이파이 환경도 고려해 제한은 너무 빡빡하지 않게 잡는다.
어떤 조합으로 쓸까
규모별 권장 조합은 이렇다.
- 소규모 사이트: 허니팟 + 시간 검증만으로도 일상적인 스팸은 거의 차단된다.
- 중규모 사이트: 여기에 reCAPTCHA v3를 추가해 타깃 공격까지 방어한다.
- 대규모·민감 사이트: 모든 계층에 서버 레이트 리밋과 이메일 도메인 블랙리스트까지 더한다.
CYAN은 홈페이지를 제작할 때 허니팟과 시간 검증을 기본으로 내장하고, 트래픽 규모에 따라 reCAPTCHA와 레이트 리밋을 추가한다. 스팸 한 통은 귀찮지만, 진짜 고객 한 명을 캡차 때문에 놓치는 건 훨씬 비싸다. 막아 내면서도 방해하지 않는 것, 그게 폼 보안의 핵심이다.