셀레니움 User-Agent 하드코딩하면 안 되는 이유 — Chrome 버전 불일치 봇 탐지
셀레니움 코드에 User-Agent를 직접 지정하는 건 흔한 패턴이다. "더 사람처럼 보이게", "Chrome으로 위장하게" 하는 용도로 많이들 쓴다. 나도 2년 전에 Chrome/114.0.0.0을 하드코딩해놓고 잘 쓰고 있었다. 그런데 어느 날 Chrome이 146으로 업데이트되면서 그 한 줄이 시한폭탄으로 변했다. UA를 하드코딩하면 안 되는 이유를 직접 겪은 사례로 정리한다.
Chrome/114
코드에 박힌 UA
Chrome/146
실제 브라우저 버전
한 줄 삭제
해결 방법
11년간 문제없던 코드가 갑자기
2025년 초에 만든 셀레니움 자동화 코드에 이런 줄이 있었다.
options.add_argument(
"user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/114.0.0.0 Safari/537.36"
)당시 최신 Chrome 버전이 114였고, 실제 Chrome을 쓰는 척 위장하기 위해 넣었다. 1년 넘게 아무 문제 없이 잘 돌아갔다. 그런데 2026년 3월, 서비스 로그인 자동화가 갑자기 50% 확률로 캡차를 맞기 시작했다.
여러 가지를 시험해보던 중 문득 Chrome 버전을 확인해봤다. 어느새 Chrome은 146이었다. 코드는 114를 보내고 있었는데 실제 브라우저는 146. 이 불일치가 문제였다.
2UA는 114인데 실제는 Chrome 146
User-Agent는 브라우저가 서버에 "나는 이런 브라우저야"라고 보내는 문자열이다. 하드코딩하면 Chrome이 아무리 업데이트돼도 항상 같은 버전 문자열이 전송된다.
| 항목 | 코드가 보내는 값 | 실제 Chrome 값 |
|---|---|---|
| User-Agent 헤더 | Chrome/114.0.0.0 | Chrome/146.0.0.0 |
| Sec-CH-UA 헤더 | 없음 (설정 안 함) | "Chromium";v="146" |
| TLS JA3 핑거프린트 | Chrome 146 패턴 | Chrome 146 패턴 |
불일치가 의심을 산다
UA는 Chrome 114라고 하는데, TLS 핑거프린트와 Client Hints(Sec-CH-UA)는 Chrome 146 패턴을 보낸다. 봇 탐지 시스템 입장에서 이건 명백한 조작의 흔적이다. 진짜 Chrome 114 사용자가 Chrome 146 TLS 패턴을 보낼 수는 없으니까.
3봇 탐지 시스템이 불일치를 잡는 방법
현대 봇 탐지 시스템은 User-Agent 문자열 하나만 보지 않는다. 여러 신호를 종합해서 "이게 진짜 사람인가"를 판단한다.
TLS JA3/JA4 핑거프린트
TLS 연결 시 브라우저가 보내는 암호화 파라미터 조합. Chrome 버전마다 고유한 패턴이 있어서 실제 Chrome 버전을 추론할 수 있다.
Sec-CH-UA (Client Hints)
Chrome 89+에서 도입된 HTTP 헤더. 브라우저가 자신의 버전을 정확하게 보내는데, UA를 조작해도 이 헤더는 실제 Chrome 버전을 반영한다.
JavaScript 엔진 특성
V8 엔진의 버전에 따라 JavaScript 실행 결과가 미묘하게 다르다. Chrome 114와 146의 V8은 분명히 다른 버전이다.
UA가 Chrome 114라고 주장하는데 Client Hints는 146이고, TLS 패턴도 146이면? 봇 탐지 시스템은 "이건 UA를 조작한 봇이다"라고 판단한다. 오히려 아무것도 건드리지 않은 것보다 더 의심받는 상황이 된다.
4한 줄 지웠더니 해결
해결책은 황당할 정도로 단순했다. UA 하드코딩 한 줄을 지우는 것.
# 수정 전 — UA 하드코딩
options.add_argument(
"user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/114.0.0.0 Safari/537.36" # ← 이 줄이 문제# 수정 후 — UA 하드코딩 제거
# user-agent 관련 코드 삭제 # Chrome이 자동으로 실제 버전 UA를 보낸다 options = uc.ChromeOptions() # 다른 옵션들만...
결과
UA 하드코딩을 제거하자 캡차 발생률이 눈에 띄게 줄었다. 여기에 undetected-chromedriver까지 적용하니 완전히 사라졌다. UA 제거만으로도 상당한 효과가 있었던 걸 보면, 불일치 탐지가 실제로 작동하고 있었던 것이다.
5UA 하드코딩이 시한폭탄인 이유
Chrome은 자동 업데이트가 기본이다. 내가 신경 쓰지 않아도 알아서 최신 버전이 된다. 코드에 박아놓은 버전 번호는 시간이 지날수록 실제와 점점 멀어진다.
| 방법 | 장점 | 단점 | 권장 |
|---|---|---|---|
| UA 하드코딩 | 코드가 단순 | Chrome 업데이트 시 불일치 발생 | 비권장 |
| UA 지정 안 함 | 실제 Chrome UA와 완벽히 일치 | 없음 | 권장 |
| 동적 버전 조회 | 항상 최신 UA | 코드 복잡도 증가 | 과함 |
UA를 굳이 지정해야 한다면
플랫폼 위장(모바일 UA 사용 등) 등 특별한 이유가 있다면, 최소한 현재 실행 중인 Chrome의 실제 버전을 자동으로 읽어서 UA를 구성해야 한다. 절대 특정 버전 숫자를 직접 박아넣지 않는다.
요약
UA 하드코딩 금지 — 핵심 요약
- ✓Chrome은 자동 업데이트되므로 UA 하드코딩은 시간이 지나면 불일치 발생
- ✓UA 버전과 TLS 핑거프린트/Client Hints 버전이 달라지면 봇으로 탐지됨
- ✓UA를 지정하지 않으면 Chrome이 실제 버전을 자동으로 보낸다
- ✓봇 탐지 우회가 목적이라면 UA 제거 + undetected-chromedriver 조합을 사용
- ✓특수한 이유로 UA를 지정해야 한다면 현재 Chrome 버전을 동적으로 읽어서 사용
본 글은 2026년 3월 실제 경험을 바탕으로 작성되었습니다. 웹 자동화는 대상 서비스의 이용약관과 robots.txt를 확인하고 허용된 범위 내에서 사용하시기 바랍니다. 본 콘텐츠의 비상업적 공유는 자유이나, 상업적 이용 시 문의 페이지를 통해 연락 바랍니다.
댓글
(2개)로그인하면 댓글을 작성할 수 있습니다.
저도 이거 때문에 며칠 날렸습니다. UA 버전이 실제 Chrome이랑 다르면 TLS 핑거프린트도 달라진다는 개념 자체를 몰랐어요.
UA를 아예 지정 안 하는 게 최선이라는 게 직관에 반하는 것 같지만 맞는 말이에요. 최신 Chrome은 Client Hints도 같이 보내니까요.
관련 글
© 2026 TreeRU. All rights reserved.
본 콘텐츠의 저작권은 TreeRU에 있으며, 출처를 밝히지 않은 무단 전재 및 재배포를 금합니다. 인용 시 출처(treeru.com)를 반드시 명시해 주세요.