Rate Limit과 Fail Limit은 어디까지가 적절할까?
최근 account 서비스에 친구 초대 코드 인증 API가 추가되면서, 해당 API에 대한 rate limit / fail limit 기준을 어떻게 가져가야 할지 고민을 했다.
초대 코드 인증은 회원가입 단계에서 호출되며, 특성상 외부 공격(브루트포스, 봇 트래픽)에 가장 먼저 노출되는 지점이기에 더 관심 있게 봤어야 했다. 이번 글에서는 실제 논의 과정과 로그 분석을 바탕으로, 어떤 기준으로 제한 정책을 잡았는지 정리해보려 한다.
왜 제한이 필요했을까?
이번에 방어하고자 했던 케이스는 크게 두 가지였다.
- 초대를 받지 않은 사용자가 초대 코드를 브루트포스로 시도하는 경우
- 회원이 아닌 사용자가 과도하게 API 요청을 보내는 경우
이미 account 서비스 전반에는 5분당 100회 수준의 rate limit이 설정되어 있었지만, 초대 코드 인증 API는 다음과 같은 특징을 가진다.
- 인증 이전 단계 (userId 없음)
- 성공/실패가 명확한 API
- 코드 값이 존재 → 브루트포스 타겟이 되기 쉬움
즉, 과도하게 사용될 수 있는 API라고 판단을 했고 이에 대한 대비로 rateLimit, failLimit을 걸고자 했다.
처음에 생각했던 구조
가장 먼저 떠올린 방식은 다음과 같은 2단 방어 구조였다.
[API Rate Limit]
├─ IP 기준 (1분 10회)
↓ 통과
[Referral Attempt Guard]
├─ 실패 카운트 누적 (Redis)
├─ 5회 연속 실패 → 10분 쿨다운
└─ 성공 시 fail_count = 0
↓ 통과
[Referral Code Validation]
- Edge 단에서 Rate Limit
- App 단에서 Fail Limit
- 성공 시에는 실패 카운트 초기화
구조 자체는 단순하지만, “과연 이 limit과 duration의 수치가 적절한지”에 대한 확신은 없었다.
- 너무 강하다면 일반 사용자에게 걸림돌이 될 수 있고
- 너무 약하다면 악용하는 사용자가 많아질 것이었다.
그래서 내부적으로만의 판단이 아닌 보안 팀의 의견을 받아 수치를 정하기로 하였다.
실제 트래픽은 어땠을까?
앱 로그를 충분히 확보하지 못한 상태라, Cloudflare 로그를 기준으로 과거 데이터를 확인해봤다.
특히 21일 이후 가입자가 급증했던 시점의 데이터를 살펴보면,
- 봇으로 보이는 IP들은
signup경로를 1분에 약 5~6회 정도 반복 호출하고 있었다.
유저 플로우상 signup과 친구 초대 인증은 호출 빈도가 비슷하다고 가정하면,
1분 10회제한은 사람 기준으로는 충분히 여유롭고, 봇 기준으로는 애매한 수치라는 판단이 들었다.
또 흥미로웠던 점은 시계열을 늘려서 보면 더 명확했다.
- 10분 기준
50회 이상호출하는 IP는 Cloudflare 기준에서도 거의 봇 트래픽으로 분류된다고 했다.
추가의견
다른 보안엔지니어 분의 말씀으로는 아래와 같은기준으로 가져가면 좋을 것 같다고 했다.
1. API Rate Limit
IP: 1분 10회(유지 가능) + 초당 burst 제한 추가
2. Referral Attempt Guard (App)
- 키: ip + device_id 우선, 가능하면 account_id도 추가
- 실패 판단: 10분 윈도우 내 실패 5회 → 10분 쿨다운
- 성공 처리: fail_count = max(0, fail_count - 1) 또는 TTL 기반 감쇠
- 단계형 백오프(가능하면)
3. Referral Code Validation
- 외부 응답은 실패 사유 통일
- 내부적으로만 실패 사유 로깅/지표화 (편집됨)
최종 결정
위와 같은 내용을 토대로, 최종적으로 아래 기준으로 진행하기로 결정했다.
1. Rate Limit
- IP 기준
- 10분 50회
2. Fail Limit
-
키:
ip또는email- (userId 생성 이전 단계이므로)
-
기준:
- 10분(마지막 시도 기준) 내 5회 연속 실패 → 10분 쿨다운
-
성공 시:
- 실패 카운트 0으로 초기화
3. 에러 로깅
- 외부 응답: 동일한 에러 메시지 (외부에서 정확한 기준을 알지 못하게 하기 위해)
- 내부 로깅: 실패 사유 분리 기록
4. Burst Limit (검토 중)
- 초당 2~3회 현재 앱에서 적용 가능한지 확인 후
마무리하며
Rate limit과 fail limit은 단순히 “얼마로 걸까?”의 문제가 아니라,
- 유저 플로우
- 실제 트래픽 패턴
- 공격자가 어떤 식으로 시도할지
를 함께 고려해야 한다는 점을 다시 한 번 느꼈습니다.
특히 이번처럼 인증 전 단계 API에서는 단순한 Rate limit만이 아닌 Fail limit도 함께 추가하여 역할을 나눠 방어하는 구조가 꽤 효과적이라는 인상을 받았습니다.