Cloudflare 무료 요금제에서 발생한 스크레이퍼 폭주: 무엇이 이를 막았고, 무엇이 꺼진 채로 남겨졌는가
운영
어느 날 아침, 우리가 운영하던 상품 상세 페이지 사이트가 열리지 않았습니다. Cloudflare는 방문자에게 524 오류를 표시했고, 원본 서버는 페이지당 2~6분이 걸렸으며, 약 10시간 동안 아무런 알림도 없었습니다. 원인은 주거용 프록시를 통해 초당 약 225건의 요청을 보내는 스크레이퍼였습니다.
폭주의 형태
- 수천 개의 주소, 각 주소당 1~3건의 요청. 미국, 스페인, 프랑스, 브라질, 영국 등지의 가정용 브로드밴드 연결로, 주거용 프록시 네트워크가 임대하는 종류의 트래픽입니다.
- Mac의 Chrome 사용자 에이전트, 버전 번호는 103부터 151까지.
- 거의 없는 쿠키 또는 Referer. 서버에서 샘플링한 2,697건의 요청 중 쿠키가 포함된 것은 4건, Referer가 포함된 것은 4건이었습니다.
- 두 가지 유형의 클라이언트. 약 절반은
Sec-Fetch-*헤더와 클라이언트 힌트를 보내지 않았습니다: 복사한 사용자 에이전트 문자열을 가진 스크립트입니다. 나머지 절반은 완전한 브라우저 헤더를 보냈습니다: 헤드리스 브라우저입니다.
모든 요청마다 모든 페이지가 렌더링되었으므로, 각 워커는 수백 개의 렌더링을 대기열에 넣고 CPU 한도에 도달했습니다.
주소별 제한이 도움이 되지 않은 이유
속도 제한은 주소별 요청 수를 계산합니다. 수천 개의 주소에서 각각 1~3건의 요청이 들어오면, 어떤 단일 주소도 제한에 근접하지 않습니다. 국가를 차단하면 우리 방문자까지 차단되었을 것입니다. 스크레이퍼가 저렴하게 흉내 낼 수 없었던 것은 이전에 사이트에 방문한 적이 있는 브라우저처럼 행동하는 것이었습니다.
Cloudflare 엣지에서: 무료 규칙 세 가지
무료 요금제는 존(zone)당 WAF 사용자 지정 규칙을 5개까지 허용합니다. 우리는 실수로 걸린 사람이 클릭하여 통과할 수 있도록 차단이 아닌 관리형 챌린지(managed challenge)를 사용하는 규칙 세 가지를 사용했습니다:
- 가짜 브라우저: 사용자 에이전트에
Chrome/이 포함되고Sec-Fetch-Mode헤더가 없는 GET 요청. 2019년 이후의 모든 Chrome은 이를 전송합니다. - 스크레이퍼 클라우드: Alibaba, Tencent, Huawei Cloud 네트워크에서 들어오는 페이지 요청. 우리가 챌린지를 부과한 트래픽의 상당 부분이 여기서 발생했습니다.
- 비상용, 기본값은 꺼짐: 쿠키가 전혀 없고 Referer도 없는 GET 요청. 사이트에 방문한 적이 있거나 링크를 통해 들어온 사람은 그대로 통과합니다. 쿠키를 저장하지 않는 스크레이퍼는 모든 요청에서 챌린지를 만납니다. 새 브라우저에 주소를 직접 입력하는 사람도 챌린지를 만나기 때문에, 폭주 중에만 이 규칙을 켭니다.
세 가지 모두 Cloudflare의 검증된 봇, 스스로를 봇으로 밝히는 사용자 에이전트, 자체 주소, API 및 웹훅 경로, 그리고 페이지가 아닌 파일을 허용합니다. 이틀 후에도 트래픽 폭주는 계속되었습니다. 1시간 동안 가짜 브라우저 규칙이 10,000건 이상의 요청을 챌린지했습니다. 쿼리당 Cloudflare가 반환하는 10,000개 이벤트는 9,627개 주소에서 발생했으며, 단일 주소당 최대 4건을 넘지 않았습니다.
오리진에서: 앱 내의 게이트
헤드리스 반쪽은 완전한 브라우저 헤더를 갖추고 있어 비상 규칙이 꺼져 있을 때 엣지 규칙만으로는 이를 잡아내지 못합니다. 앱 자체에서는 페이지 렌더러 앞에 작은 미들웨어를 배치했습니다:
Sec-Fetch-Mode도 클라이언트 힌트도 없는 Chrome 사용자 에이전트는 작업 수행 전에 403을 받습니다;- 당사의 쿠키도 Referer도 없는 낯선 방문자는 워커에 여유 용량이 있을 때만 초당 몇 페이지 수준으로 서비스를 받습니다. 이를 초과하면 400바이트 크기의 503 페이지가 쿠키를 설정하고 2초 후 새로고침합니다. 사람은 두 번째 시도에서 페이지를 받지만, 쿠키를 저장하지 않는 스크래퍼는 결코 페이지를 받지 못합니다.
게이트가 작동한 첫 1분 동안 약 6,700개의 가짜 브라우저를 거부하고 약 6,700명의 낯선 방문자를 돌려보냈으며, 낯선 방문자에게 초당 약 9페이지를 서비스했습니다. 느린 요청은 0으로 떨어졌고, 워커의 CPU는 상한선에서 12~15%로, 메모리는 각 4~5GB에서 0.65GB로 감소했습니다.
꺼둔 것들
- Bot Fight Mode. 자동화된 트래픽을 챌린지하며 Free 요금제에서는 맞춤 규칙으로 우회할 수 없고, 결제 제공업체의 웹훅을 잡아냈습니다.
- 전체 존에 대한 Under Attack 모드. 모든 방문자, API 클라이언트 및 웹훅을 인터스티셜 페이지를 거치도록 합니다. 비상 규칙은 낯선 방문자의 페이지 요청에만 동일한 역할을 수행합니다.
- Free 요금제의 속도 제한 규칙. 주소별로 카운트하는데, 이번 트래픽 폭주는 이를 트리거하지 않습니다.
- AI 크롤러 차단. AI 검색 어시스턴트에게 발견되기를 원하며, 해당 크롤러들은 문제가 아니었습니다.
핵심 요약
주거용 프록시를 통한 트래픽 폭주는 부재한 요소로 쉽게 식별할 수 있습니다: 브라우저 fetch 헤더, 쿠키 및 Referer. 엣지에서 이를 챌린지하고, 낯선 방문자를 워커가 렌더링할 수 있는 범위로 제한하며, 서버 외부에서 페이지가 열리지 않을 때 감지할 수 있는 수단을 확보하십시오. Night Watch는 세 가지를 모두 패키징합니다: 워치, 비상 규칙용 자동 스위치가 포함된 규칙, 그리고 Python 웹 앱을 위한 게이트.