봇 차단은 헤더 하나가 아니다 — 막는 쪽에서 본 다섯 층
연결 · 요청 · 페이지 · 입력 · 세션이 같은 이야기를 하는지 보고 점수를 매긴다
Reddit 과 Naver 가 브라우저를 조작하는 AI 를 못 들어오게 한다는 말을 듣고, 처음엔 「User-Agent 헤더 하나 보는 거겠지」 라고 생각했다. 찾아 보니 아니었다. 지금의 봇 관리는 헤더 하나가 아니라 여러 층의 신호가 서로 맞는지를 보고 점수를 매긴다. 사이트를 운영하는 쪽, 막는 쪽에서 정리했다. 내 서비스에 봇 대책을 넣을 때 무엇부터 정할지가 보인다.
흔히 떠올리는 그림과 실제
흔히: 요청 ── User-Agent ──▶ 허용 / 거절
실제로 앞단이 보는 건 층이 여럿이다. Cloudflare 가 문서로 공개한 구조를 기준으로 그렸다. 사이트마다 앞단은 다를 수 있다.
| 층 | 보는 것 | 막는 쪽이 얻는 신호 |
|---|---|---|
| 연결 | TLS 첫 인사(ClientHello) 지문, HTTP/2 설정 | 스크립트용 HTTP 클라이언트와 실제 브라우저는 여기부터 다르다 |
| 요청 | 헤더 종류 · 순서, client hint, sec-fetch-* |
UA 가 말하는 브라우저와 다른 헤더가 가리키는 브라우저가 다르면 그 불일치가 신호 |
| 페이지 안 | 자바스크립트로 보는 브라우저 환경 | 헤드리스 · 자동화 도구의 흔적 |
| 입력 | 클릭 · 키 이벤트가 실제 입력인지 | 스크립트가 만든 이벤트 |
| 세션 | IP 평판, 요청 간격, 계정 이력 | 요청 하나가 깨끗해도 쌓이는 행동 |
User-Agent 를 바꾸는 건 이 표의 둘째 줄 안 한 칸만 건드린다. 나머지 층이 다른 이야기를 하면 점수는 그대로 남는다.
점수는 1〜99
Cloudflare 봇 점수 문서에 따르면 점수는 1〜99 이고 낮을수록 자동화일 가능성이 높다. 엔진은 휴리스틱(알려진 지문과 대조), 머신러닝, 자바스크립트 탐지로 나뉜다. 휴리스틱에 확실히 걸린 요청은 1 을 받는다.
연결 층의 대표가 JA3 · JA4 같은 TLS 지문이다. JA4 는 ClientHello 의 확장 목록을 정렬해서 만드는 지문으로, JA3 를 다듬은 것이다. 다만 세밀한 점수와 JA3 · JA4 값은 Bot Management 를 산 Enterprise 고객에게만 보인다. Pro 이상 플랜은 「자동화 · 사람」 묶음으로 본다.
한 번 통과해도 끝이 아니다. Cloudflare 는 2026-08 블로그에서 세션 내내 클라이언트 행동을 보는 탐지를 공개했다. 캡차가 그 순간의 관문이라면, 행동 점수는 그 뒤의 세션을 본다.
Reddit 은 헤더가 아니라 통로를 좁혔다
The Verge(2026-09-30)가 전한 Reddit 의 설명은 이렇다. Old Reddit 은 로그인을 요구하고, 전환 시점 기준 최근 6개월 안에 쓴 계정만 남긴다. RSS 는 2026-11-13 에 끊는다. 이유는 대규모 스크래핑과 자동 악용이다.
「AI 브라우저 헤더를 거른다」 가 아니라 통로와 계정을 좁힌 것이다. 막는 쪽에서 보면 이게 제일 싸다. 지문 싸움은 끝이 없지만, 익명으로 열린 통로를 닫는 건 한 번이면 된다.
Naver 쪽은 「이 헤더면 에이전트 브라우저로 본다」 는 공개 문서를 찾지 못했다. Yeti 는 Naver 가 밖으로 보내는 수집기 이름이지, 들어오는 브라우저를 거르는 표시가 아니다. Naver 가 어느 층에서 막는지는 확인하지 못해서 여기 쓰지 않는다.
내 서비스라면 — 언제 무엇을
| 상황 | 먼저 할 것 |
|---|---|
| 로그인 · 가입 폼에 자동 시도가 몰린다 | 요청 빈도 제한(rate limit)과 캡차 |
| 공개 API · RSS 를 긁어 간다 | 통로를 인증 뒤로 옮기거나 키를 발급 |
| 사람인 척하는 브라우저 자동화가 문제 | 앞단 봇 관리(Cloudflare 등)의 점수를 받아 규칙으로 |
Rails 라면 첫 줄은 컨트롤러 한 줄로 시작할 수 있다. Rails 7.2 부터 들어간 rate_limit 이다.
class SessionsController < ApplicationController
rate_limit to: 10, within: 3.minutes, only: :create
end
User-Agent 차단 목록만 두는 건 가장 약한 칸 하나만 지키는 셈이다. 이름을 정직하게 밝히는 수집기를 정리하는 데는 쓸모가 있다. 숨기려는 쪽은 그 칸부터 바꾼다.
직접 해 보지 않은 것도 적어 둔다. Reddit · Naver 에 자동화 브라우저를 보내 어느 층에서 거절되는지 재현하지 않았다. 점수의 가중치도 공개돼 있지 않다.
서비스에 봇 · 스크래핑 대책을 어디까지 넣을지, 로그인과 API 통로를 어떻게 나눌지 고민이라면 https://www.negabaro.com/contact 로 물어봐도 된다.
동작 흐름
연결: TLS ClientHello · HTTP/2 설정으로 클라이언트 종류를 본다
요청: 헤더 순서 · client hint 가 UA 와 맞는지 본다
페이지 · 입력: 자바스크립트로 환경과 이벤트를 확인한다
세션: IP · 간격 · 계정 이력을 쌓아 1〜99 점수로 허용 · 챌린지 · 차단