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 방어 시스템을 통해 대규모 공격을 네트워크 레벨에서 차단합니다.