Request Header Filtering: User-Agent 제어 AtoZ
User-Agent는 클라이언트(브라우저, 모바일 앱, 검색엔진 봇 등)가 서버에 자신의 정체를 알리기 위해 보내는 요청 헤더(Request Header)의 한 종류입니다. 서버는 이 User-Agent 값을 보고 요청의 출처를 파악하여 다양한 제어를 수행할 수 있습니다.
이 글에서는 User-Agent를 제어하는 이유부터 구체적인 기술 구현 방법, 그리고 모범 사례까지 'A to Z' 형식으로 상세하게 설명합니다.
1. 왜 User-Agent를 제어해야 하는가? (The "Why")
User-Agent 필터링은 다음과 같은 다양한 목적으로 사용됩니다.
- 악성 봇(Malicious Bot) 차단: 웹사이트의 콘텐츠를 무단으로 수집(Scraping)하거나, 취약점을 스캔하는 등 악의적인 활동을 하는 봇의 접근을 차단합니다.
- 특정 크롤러(Crawler) 제어: Google, Naver 같은 검색엔진 봇의 접근은 허용하되, 원치 않는 검색엔진이나 마케팅 봇의 접근은 차단하여 불필요한 트래픽과 서버 부하를 줄입니다.
- 서비스별 접근 제어: 특정 모바일 앱(예:
MyAwesomeApp/1.0)에서만 API 접근을 허용하거나, 웹 브라우저와 앱의 요청을 구분하여 다른 콘텐츠를 제공할 수 있습니다. - 오래된 브라우저 지원 중단 안내: Internet Explorer 구 버전과 같이 보안에 취약하거나 특정 기능을 지원하지 않는 브라우저 사용자에게 업데이트를 권장하거나 서비스 이용이 제한됨을 안내합니다.
- A/B 테스팅 및 통계 수집: 특정 브라우저나 기기 사용자 그룹에만 새로운 기능을 노출하거나, 사용자 환경 통계를 정교하게 수집하는 데 활용됩니다.
2. 제어 전략: 블랙리스트 vs. 화이트리스트
User-Agent를 제어하는 방식은 크게 두 가지 전략으로 나뉩니다.
| 전략 | 설명 | 장점 | 단점 | 추천 사용 사례 |
|---|---|---|---|---|
| 블랙리스트 (Blacklist) | 차단할 특정 User-Agent 목록을 만들어 해당 요청을 거부하는 방식입니다. | 구현이 간단하고, 정상적인 대부분의 사용자는 영향을 받지 않습니다. | 새로운 악성 봇이 나타날 때마다 목록을 계속 업데이트해야 합니다. | 일반적인 웹사이트에서 알려진 악성 봇이나 원치 않는 크롤러를 차단할 때 |
| 화이트리스트 (Whitelist) | 허용할 특정 User-Agent 목록을 만들어, 그 외의 모든 요청을 거부하는 방식입니다. | 매우 강력한 보안을 제공합니다. (Default-Deny) | 허용 목록에 없는 정상적인 사용자(예: 신규 브라우저)의 접근을 차단할 수 있어 관리가 까다롭습니다. | 특정 클라이언트(자사 앱 등)만 접근해야 하는 폐쇄적인 API 서버 |
일반적으로 블랙리스트 방식이 더 널리 사용되며, 두 가지를 혼합한 하이브리드 전략을 사용하기도 합니다.
3. 제어 방법: 구현 계층별 AtoZ (The "How")
User-Agent 필터링은 인프라의 여러 계층에서 구현할 수 있습니다. 앞단에서 처리할수록 애플리케이션 서버의 부하를 줄일 수 있어 효율적입니다.
A. 웹 서버 (Web Server)
가장 기본적인 제어 지점입니다. 웹 서버 설정을 통해 특정 User-Agent를 차단할 수 있습니다.
Nginx
map 지시어를 사용하는 것이 if문보다 성능상 권장됩니다. 특정 User-Agent를 변수($block_user_agent)로 매핑하고, 이 변수 값을 보고 접근을 차단합니다.
# nginx.conf
# 1. 차단할 User-Agent 목록을 map으로 정의 (정규표현식 사용 가능)
# ~* : 대소문자 구분 없는 정규표현식 매칭
map $http_user_agent $block_user_agent {
default 0;
~* (AhrefsBot|SemrushBot|MJ12bot|DotBot) 1; # 알려진 마케팅/백링크 봇
~* (python-requests|curl|wget) 1; # 의심스러운 라이브러리/툴
"BadBot/1.0" 1; # 특정 문자열
}
server {
listen 80;
server_name yourdomain.com;
# 2. map 변수 값이 1이면 403 Forbidden 에러 반환
if ($block_user_agent) {
return 403;
}
# ... 기타 설정 ...
}
Apache
.htaccess 파일과 mod_rewrite 모듈을 사용하여 구현합니다.
# .htaccess
# mod_rewrite 활성화
RewriteEngine On
# 차단할 User-Agent 조건을 설정 (OR 조건으로 여러 개 추가 가능)
RewriteCond %{HTTP_USER_AGENT} AhrefsBot [NC,OR]
RewriteCond %{HTTP_USER_AGENT} SemrushBot [NC,OR]
RewriteCond %{HTTP_USER_AGENT} "python-requests" [NC]
# 위 조건에 하나라도 해당하면 403 Forbidden 페이지로 보냄
# [F] = Forbidden (403), [L] = Last (이후 규칙 처리 중단)
RewriteRule .* - [F,L]
[NC] 플래그는 'No Case'를 의미하며, 대소문자를 구분하지 않습니다.
B. WAF (Web Application Firewall) / CDN
Cloudflare, AWS WAF, Akamai 같은 서비스를 이용하면 코드나 서버 설정을 직접 수정하지 않고도 강력한 필터링이 가능합니다.
- 작동 방식: 서비스 대시보드에서 보안 규칙을 생성합니다.
- 규칙 조건으로 'Header'를 선택하고 헤더 이름으로 'User-Agent'를 지정합니다.
- 매칭 조건(포함, 일치, 정규표현식 등)과 차단할 User-Agent 문자열을 입력합니다.
- 해당 규칙에 매칭될 때 수행할 액션(예:
Block,Challenge)을 설정합니다.
- 장점:
- 애플리케이션 서버에 도달하기 전에 차단하여 서버 부하가 전혀 없습니다.
- 미리 정의된 '악성 봇 목록'을 제공하여 손쉽게 적용할 수 있습니다.
- GUI 기반으로 설정이 간편합니다.
C. 애플리케이션 레벨 (Application Level)
웹 서버나 WAF에서 처리하기 힘든 복잡한 비즈니스 로직이 필요할 때 애플리케이션 코드 내에서 직접 제어합니다.
Java (Spring Boot - Filter)
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
@Component
public class UserAgentFilter implements Filter {
private final List blockedUserAgents = Arrays.asList("BadBot", "python-requests");
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
String userAgent = httpRequest.getHeader("User-Agent");
if (userAgent != null && blockedUserAgents.stream().anyMatch(userAgent::contains)) {
httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN, "Access Denied");
return;
}
chain.doFilter(request, response);
}
}
Node.js (Express - Middleware)
const express = require('express');
const app = express();
const blockUserAgent = (req, res, next) => {
const userAgent = req.get('User-Agent') || '';
const blockedAgents = ['BadBot', 'python-requests'];
const isBlocked = blockedAgents.some(agent => userAgent.includes(agent));
if (isBlocked) {
res.status(403).send('Forbidden');
} else {
next();
}
};
// 미들웨어를 모든 라우트에 적용
app.use(blockUserAgent);
app.get('/', (req, res) => {
res.send('Hello World!');
});
app.listen(3000);
4. 모범 사례 및 고려사항
- 정규 표현식 최적화: 복잡하고 비효율적인 정규 표현식은 오히려 서버 성능을 저하시킬 수 있습니다. (ReDoS 공격에 유의)
- 대소문자 처리: User-Agent 문자열은 대소문자가 다를 수 있으므로, 비교 시에는 항상 대소문자를 구분하지 않도록 처리하는 것이 안전합니다. (예: Nginx의
~*, Apache의[NC]) - 오탐(False Positive) 최소화: 너무 광범위한 키워드(예: 'bot')로 차단하면 Googlebot 같은 정상적인 봇이나 일부 브라우저까지 차단할 수 있습니다. 최대한 구체적인 문자열로 차단하고, 항상 테스트를 거쳐야 합니다.
- 로깅(Logging)은 필수: 어떤 User-Agent가 차단되었는지 로그를 남겨야 합니다. 이를 통해 오탐 여부를 분석하고 차단 목록을 지속적으로 개선할 수 있습니다.
- 지속적인 업데이트: 악성 봇의 User-Agent는 계속해서 변화하고 우회 기술도 발전하므로, 차단 목록은 정기적으로 검토하고 업데이트해야 합니다.
- User-Agent는 절대적인 보안 수단이 아님: User-Agent 헤더는 클라이언트가 쉽게 변조할 수 있습니다. 따라서 User-Agent 필터링은 IP 기반 차단, Rate Limiting(요청 빈도 제한) 등 다른 보안 장치와 함께 계층적 방어(Defense in Depth)의 일부로 사용해야 합니다.
5. 결론
User-Agent 필터링은 서비스의 안정성을 높이고 보안을 강화하며, 특정 사용자 그룹에 맞춤형 경험을 제공하는 효과적인 수단입니다.
제어는 WAF/CDN > 웹 서버 > 애플리케이션 순으로 앞단에서 처리하는 것이 효율적입니다. 서비스의 규모, 보안 요구사항, 개발 리소스 등을 종합적으로 고려하여 가장 적합한 계층에서, 올바른 전략(블랙리스트/화이트리스트)으로 구현하는 것이 중요합니다. 항상 로깅과 모니터링을 통해 규칙을 지속적으로 개선해 나가는 노력이 동반되어야 합니다.
'Security' 카테고리의 다른 글
| 국가망 보안체계 가이드라인 (2) | 2025.08.27 |
|---|---|
| APT 공격 심층 분석 및 대응 가이드 (0) | 2025.08.22 |
| 중소기업 침해사고 피해지원 서비스 동향 보고서 (0) | 2025.08.21 |
| 2025 상반기 사이버 위협 동향 리포트 (5) | 2025.08.19 |
| 랜섬웨어 대응 보안 강화 가이드 (1) | 2025.08.19 |