Nginx 접속 로그에는 서버로 들어오는 모든 요청 정보가 담겨 있습니다. 로그를 분석하면 악성 봇, 보안 스캐너, DDoS 공격 패턴을 파악하고 차단할 수 있습니다.
로그 형식 이해
# /etc/nginx/nginx.conf의 기본 로그 형식
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';
# 로그 샘플
203.0.113.55 - - [15/Jul/2024:03:24:15 +0900] "GET /wp-login.php HTTP/1.1" 404 162 "-" "Mozilla/5.0 zgrab/0.x"
기본 로그 분석 명령어
# 접속 로그 경로
ACCESS_LOG="/var/log/nginx/access.log"
# 상위 10개 접속 IP
awk '{print $1}' $ACCESS_LOG | sort | uniq -c | sort -rn | head -10
# HTTP 상태 코드별 집계
awk '{print $9}' $ACCESS_LOG | sort | uniq -c | sort -rn
# 상위 10개 요청 URL
awk '{print $7}' $ACCESS_LOG | sort | uniq -c | sort -rn | head -10
# 특정 IP의 요청 내역
grep "203.0.113.55" $ACCESS_LOG
# 404 오류가 많은 URL (스캐너 탐지)
awk '$9 == 404 {print $7}' $ACCESS_LOG | sort | uniq -c | sort -rn | head -20
# User-Agent별 집계
awk -F'"' '{print $6}' $ACCESS_LOG | sort | uniq -c | sort -rn | head -10
악성 봇 식별 패턴
# WordPress 공격 스캐너 탐지
grep "wp-login\|xmlrpc\|wp-config\|eval(" $ACCESS_LOG | awk '{print $1}' | sort | uniq -c | sort -rn
# 알려진 취약점 스캔 패턴
grep -E "\.env|\.git/|phpmyadmin|admin|setup\.php|shell\.php" $ACCESS_LOG | awk '{print $1}' | sort | uniq -c | sort -rn
# 비정상적으로 많은 요청 (초당 100건 이상)
awk '{print $4}' $ACCESS_LOG | cut -d: -f1,2,3 | sort | uniq -c | sort -rn | head
# 알려진 악성 User-Agent
grep -i "zgrab\|masscan\|nikto\|sqlmap\|acunetix\|nessus\|nmap\|dirbuster" $ACCESS_LOG
Nginx에서 악성 봇 차단
User-Agent 기반 차단
# /etc/nginx/conf.d/block-bots.conf
map $http_user_agent $bad_bot {
default 0;
~*zgrab 1;
~*masscan 1;
~*nikto 1;
~*sqlmap 1;
~*acunetix 1;
~*nessus 1;
~*dirbuster 1;
~*python-requests 1;
~*Go-http-client 1;
~*curl 0; # curl은 허용 (개발자 도구로 사용)
}
server {
if ($bad_bot) {
return 444; # 연결 즉시 종료 (응답 없음)
}
}
IP 기반 차단
# /etc/nginx/conf.d/block-ips.conf
geo $blocked_ip {
default 0;
203.0.113.55 1;
198.51.100.0/24 1;
}
server {
if ($blocked_ip) {
return 444;
}
}
요청 속도 제한으로 봇 차단
# nginx.conf (http 블록)
limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
limit_req_zone $binary_remote_addr zone=login:10m rate=3r/m;
server {
# API 엔드포인트
location /api/ {
limit_req zone=api burst=20 nodelay;
limit_req_status 429;
}
# 로그인 페이지 (브루트포스 방어)
location /wp-login.php {
limit_req zone=login burst=5;
limit_req_status 429;
}
}
악성 요청 패턴 차단
server {
# 숨겨진 파일 접근 차단 (.env, .git 등)
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
# 민감한 파일 직접 접근 차단
location ~* \.(env|sql|bak|backup|config|log)$ {
deny all;
}
# PHP 파일 업로드 디렉터리에서 실행 차단
location ~* /uploads/.*\.php$ {
deny all;
}
# 비정상 요청 메서드 차단
if ($request_method !~ ^(GET|POST|HEAD|OPTIONS)$) {
return 405;
}
}
GoAccess로 실시간 시각화
# GoAccess 설치
sudo apt install -y goaccess
# 터미널에서 실시간 분석
sudo goaccess /var/log/nginx/access.log --log-format=COMBINED
# HTML 리포트 생성
sudo goaccess /var/log/nginx/access.log \
--log-format=COMBINED \
-o /var/www/html/report.html \
--real-time-html \
--daemonize
# 특정 기간 분석
zcat /var/log/nginx/access.log.*.gz | goaccess --log-format=COMBINED
자동 차단 스크립트
#!/bin/bash
# /opt/auto-block.sh
# 10분 내 500회 이상 요청한 IP 자동 차단
LOG="/var/log/nginx/access.log"
THRESHOLD=500
WINDOW=600 # 10분 (초)
# 최근 10분간 로그만 분석
START_TIME=$(date -d "-${WINDOW} seconds" '+%d/%b/%Y:%H:%M:%S')
awk -v start="$START_TIME" '
{
# 타임스탬프 파싱
split($4, t, ":");
if (t[2]":"t[3]":"t[4] >= substr(start, 13)) {
count[$1]++
}
}
END {
for (ip in count) {
if (count[ip] > '"$THRESHOLD"') {
print ip, count[ip]
}
}
}' $LOG | while read ip count; do
if ! sudo ufw status | grep -q "$ip"; then
sudo ufw insert 1 deny from $ip
echo "$(date): Blocked $ip ($count requests in ${WINDOW}s)" >> /var/log/auto-block.log
fi
done
# 5분마다 실행
echo "*/5 * * * * root /opt/auto-block.sh" | sudo tee /etc/cron.d/auto-block
로그 분석을 통한 사전 차단이 DDoS나 봇 공격을 효율적으로 막는 방법 중 하나입니다. TCP-80.NET은 자체 DDoS 방어 시스템을 통해 대규모 공격을 네트워크 레벨에서 차단합니다.