AJAX 요청 제외
목차
보안 필터는 한 번 만들어놓고 계속 방치하는 컴포넌트 중 하나다. 잘 돌아가면 아무도 신경 안 쓰고, 문제가 생겨야 부랴부랴 들여다보게 됨. 이번에는 조용히 문제가 터지기 전에 미리 손봤는데, 작업 자체는 작았어도 짚고 넘어갈 게 생각보다 많았다.
운영 서버에 붙어있는 보안 필터는 크게 세 가지를 처리한다. IP 기반 Rate Limit, 봇/공격 패턴 감지, 블랙리스트 자동 등록. 각각 독립적으로 동작하는 것 같지만 실제로는 하나의 흐름 안에서 순서대로 걸린다.
요청 수신
→ 화이트리스트 IP 확인
→ 봇 UA / 의심 경로 감지
→ Rate Limit 체크 (Redis 슬라이딩 윈도우)
→ 차단 / 블랙리스트 등록 / 통과
순서가 중요하다. 화이트리스트 확인을 앞에 두는 건 이후 로직을 전부 skip시키기 위해서고, 봇 패턴 감지를 Rate Limit보다 앞에 두는 건 카운트 비용 자체를 아끼기 위해서다. Redis 슬라이딩 윈도우는 정확하지만 요청마다 incr + expire 연산이 붙기 때문에, 어차피 차단할 봇 트래픽은 앞에서 걸러내는 게 맞다.
이번 변경 내용
| 항목 | 기존 | 변경 후 |
|---|---|---|
| Rate Limit 임계값 | 완화 상태 | 강화 (1분 기준 하향) |
| 공격 패턴 감지 | 기본 | 의심 경로 + 페이로드 확장 |
| 블랙리스트 | 수동 | DB 자동 등록 |
임계값 완화 상태가 얼마나 지속됐는지는 정확히 모르겠는데, 어느 시점에 헐겁게 열어놓은 채 그냥 굳어진 것 같았다. 이번에 1분 기준으로 다시 조여줬다. 공격 패턴 감지도 의심 경로 리스트와 페이로드 패턴을 추가했는데, 기본 패턴만으로는 변형된 스캐닝 시도를 잡기 어려운 경우가 있어서임.
예외 경로 처리는 이런 강화 작업마다 항상 세트로 따라온다. 헬스체크 엔드포인트나 모니터링 수집 경로가 필터에 걸리면 운영 알림이 다 깨진다. 예외 처리 없이 임계값을 낮췄다가 내부 모니터링이 막혀 롤백한 케이스를 본 적이 있는데, 그때 이후로 예외 경로는 무조건 먼저 정리하고 강화 작업에 들어가는 습관이 생겼다.
AJAX 요청 Rate Limit 제외 처리
이번 작업에서 가장 고민이 많았던 부분이다.
페이지 로드할 때 AJAX 요청이 많이 나가는 구조가 있다. 초기 렌더링 이후 여러 컴포넌트가 각자 데이터를 끌어오는 방식이면, 사용자 한 명이 페이지 하나 여는 데 요청이 여러 개씩 나갈 수 있음. 이걸 일반 페이지 요청과 동일한 기준으로 카운트하면, 정상 사용자가 Rate Limit에 걸리는 상황이 만들어진다.
해결 방향은 두 가지였다.
- AJAX 요청을 Rate Limit 카운트에서 완전 제외
- AJAX 요청에 별도 버킷 적용 (더 높은 임계값으로 분리)
별도 버킷을 만드는 게 더 정교한 방식이긴 한데, 지금 구조에서 버킷을 추가하면 관리 포인트가 늘어난다. 임계값 두 개를 따로 관리해야 하고, 버킷 간 연동 로직도 필요해진다. 완전 제외가 단순하고, 당장 AJAX 경로를 통한 공격 패턴이 별도로 있는 상황이 아니라 이쪽을 선택했다.
판단 근거는 요청 헤더의 X-Requested-With: XMLHttpRequest 값이다. 이게 조작될 수 있다는 점은 알고 있는데, 현재 구조에서 봇이 이 헤더를 정확히 세팅해서 Rate Limit를 우회할 가능성보다 정상 사용자가 막히는 문제가 더 크다고 봤음. 트레이드오프를 감수하고 가는 거다. 나중에 AJAX 경로만 노리는 스캐닝이 보이면 그때 버킷 분리로 전환할 생각이다.
블랙리스트 자동 등록과 오탐 대응
공격성 요청이 감지됐을 때 수동으로 IP를 등록하는 방식은 타이밍을 못 맞춘다. 패턴을 발견하고 알림 확인하고 수동 등록하는 사이에 요청이 더 들어올 수 있음. DB 자동 등록 구조로 전환하면서 감지 즉시 다음 요청부터 차단되도록 만들었다.
자동 등록이 빠른 대신 오탐 리스크가 생긴다. 이걸 줄이기 위한 기본 원칙들은:
- 내부 배치 작업이나 로드 테스트 IP는 미리 화이트리스트에 넣어두기. 자동 등록 이후 예외처리는 구조가 복잡해짐.
- 영구 차단 대신 TTL 설정. 오탐으로 막힌 IP가 있을 때 자동으로 풀릴 수 있게. 공격성이 명확한 건 TTL을 길게, 패턴이 애매한 건 짧게 가는 게 맞다.
- 자동 등록 시 슬랙/디스코드 알림 연동. 완전히 자동화하더라도 어떤 IP가 왜 막혔는지는 눈으로 계속 봐야 한다. 오탐 패턴이 보이면 감지 조건을 수정해야 하는데, 알림 없이는 그 신호 자체를 잡기 어렵다.
이런 설정 레이어는 변경 규모는 작아도 실제 서비스 안정성에 영향을 미치는 범위가 넓다. Rate Limit 임계값 하나 잘못 건드리면 정상 트래픽을 막고, 예외 처리를 빠뜨리면 내부 모니터링이 깨진다. 변경 이력을 명시적으로 남겨두는 게 이런 컴포넌트에서 특히 의미 있는 이유가 여기 있다. 나중에 왜 이 값으로 바꿨는지 기억 못하면 다시 완화 상태로 돌아가는 사이클이 반복된다.
댓글 0
첫 댓글 달아줘.