← 전체 글로 돌아가기

API

작은 API에 rate limit을 넣기 전 응답 기준부터 정한 설정 노트

로그인과 문의 API에 제한을 추가하면서 상태 코드와 프록시 신뢰 범위를 정한 메모.

숫자보다 먼저 정한 기준

문의 폼 로그에 같은 IP의 POST가 짧은 시간에 수십 번 쌓였다. DB보다 이메일 알림이 먼저 묻혔다. 처음에는 분당 10회라는 숫자만 넣으려 했지만 로그인과 문의 API를 같은 정책으로 묶으면 정상 사용자를 막을 수 있었다.

엔드포인트를 나눴다

로그인은 짧고 엄격하게, 문의는 새로고침을 고려해 더 길게 잡았다. 메모리 저장소는 개발용이고 여러 서버에서는 Redis처럼 공유 저장소가 필요하다.

const policy = {
  login: { limit: 5, windowMs: 60_000 },
  contact: { limit: 3, windowMs: 600_000 },
};

제한 시에는 프론트가 구분할 수 있게 429와 재시도 시간을 보냈다.

return Response.json({ message: '잠시 후 다시 시도해 주세요.' }, {
  status: 429, headers: { 'Retry-After': '60' }
});

프록시 헤더의 함정

로컬에서는 x-forwarded-for를 바로 읽어도 되지만, 공개 서버가 클라이언트 헤더를 그대로 받으면 IP를 위조할 수 있다. 내가 관리하는 Nginx가 덮어쓰는 경로에서만 신뢰한다.

proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

적용 확인

  • 연속 클릭에서 429와 안내가 보이는지 확인한다.
  • Retry-After를 응답한다.
  • 다중 인스턴스의 카운터를 공유한다.
  • IP 로그는 필요한 범위만 마스킹한다.

rate limit은 끝이 아니라 알림과 비용을 지키는 첫 울타리다.