본문 바로가기

메모

GeoIP를 활용한 Nginx 국가별 접근 차단: 당신의 웹사이트를 지키는 글로벌 관문 🌍 🗝️

728x90

추억의 울트라맨과 괘씸한 공격 로그

새벽에 일어나(백수라도 일찍 일어나는 부지런함!) 서버 상태를 확인하기 위해서 로그를 살펴보던 중 해외에서 지속적으로 공격이 들어오는 것을 확인했다.

 

대부분의 페이로드는 숨겨진 파일을 찾거나, 관리자 페이지에 접근하기 위한 일반적인 CMS 관리자 페이지, 또는 개발자가 실수로 배포에 포함될 수 있는 메타데이터 파일 등을 주로 탐색하는 것으로 파악된다.

 

대부분의 공격 요청을 추적해보면 해외 호스팅 서비스를 경유하는 경우가 많아 현재 서비스는 해외 대상으로 진행 중인 것이 없어 국내 IP만 요청을 받도록 설정하려고 한다.

 

현재 내부 서비스는 reverse-proxy로 연결되어 있기 때문에 NGINX 단에서 특정 국가에서 발급된 IP는 요청을 차단하는 형태가 가장 일반적인 방식일 것 같아 npx_http_geoip_module을 도입할 예정이다.

Round 1... fight!

일단 하기로 마음 먹었으니 nginx module을 추가하려고 터미널을 열어 이것저것 삽질을 하다가 첫 번째 라운드는 nginx가 승리했다.

 

기존에 사용하던 nginx에서는 빌트-인 모듈이 아닌 '--with-http_geoip_module'이 포함되어있지 않아, 다시 컴파일 할 필요가 있는데, 현재 프록시를 담당하는 인스턴스가 Proxmox의 LXC라 이 과정이 꽤나 복잡하고 번거러웠다.

 

그래서 하는 수 없이 VM을 띄워 ubuntu에서 진행하기로 결정했다.

Round 2... fight!

VM으로 넘어와서는 굉장히 순조롭게 진행돼 20분만에 설정이 마무리가 됐다. 일단 필요한 의존성을 추가하는 것으로 시작하자.

의존성 설치

sudo apt-get install make libperl-dev \
libpcre3 libpcre3-dev zlib1g zlib1g-dev \
openssl libssl-dev libxml2-dev libxslt1-dev \
libgd-dev libgeoip-dev google-perftools \
libgoogle-perftools-dev gcc g++ linux-headers-$(uname –r)

Nginx 설치

그리고 컴파일 하기 위한 nginx 소스 코드를 다운로드 받는다.

$ wget https://nginx.org/download/nginx-1.24.0.tar.gz
$ tar zxvf nginx-1.24.0.tar.gz
$ cd nginx-1.24.0

다음 컴파일 하기 전 설정을 지정한다.

./configure --prefix=/usr/share/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --http-client-body-temp-path=/var/lib/nginx/tmp/client_body --http-proxy-temp-path=/var/lib/nginx/tmp/proxy --http-fastcgi-temp-path=/var/lib/nginx/tmp/fastcgi --http-uwsgi-temp-path=/var/lib/nginx/tmp/uwsgi --http-scgi-temp-path=/var/lib/nginx/tmp/scgi --pid-path=/run/nginx.pid --lock-path=/run/lock/subsys/nginx --user=nginx --group=nginx --with-compat --with-debug --with-file-aio --with-http_addition_module --with-http_auth_request_module --with-http_dav_module --with-http_degradation_module --with-http_flv_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module=dynamic --with-http_mp4_module --with-http_perl_module=dynamic --with-http_random_index_module --with-http_realip_module --with-http_secure_link_module --with-http_slice_module --with-http_ssl_module --with-http_stub_status_module --with-http_sub_module --with-http_v2_module --with-http_xslt_module=dynamic --with-mail=dynamic --with-mail_ssl_module --with-pcre --with-pcre-jit --with-stream=dynamic --with-stream_ssl_module --with-stream_ssl_preread_module --with-threads --with-http_geoip_module

 

다음은 바로 컴파일&설정!

$ sudo make && sudo make install
$ sudo chmod +x /usr/sbin/nginx
$ sudo mkdir -p /var/log/nginx
$ sudo mkdir -p /var/lib/nginx/tmp/client_body

서비스 데몬 추가

이제 nginx를 서비스로 등록하면 설치~실행까지는 마무리!

[Unit]
Description=The nginx HTTP and reverse proxy server
After=network-online.target remote-fs.target nss-lookup.target
Wants=network-online.target

[Service]
Type=forking
PIDFile=/run/nginx.pid
# Nginx will fail to start if /run/nginx.pid already exists but has the wrong
# SELinux context. This might happen when running `nginx -t` from the cmdline.
# https://bugzilla.redhat.com/show_bug.cgi?id=1268621
ExecStartPre=/usr/bin/rm -f /run/nginx.pid
ExecStartPre=/usr/sbin/nginx -t
ExecStart=/usr/sbin/nginx
ExecReload=/usr/sbin/nginx -s reload
KillSignal=SIGQUIT
TimeoutStopSec=5
KillMode=mixed
PrivateTmp=true

[Install]
WantedBy=multi-user.target

/lib/systemd/system/nginx.service에 위 코드를 추가한 후 sudo systemctl start nginx.service를 하면 된다 :>

GeoIP 설정

땡!

일단 클라이언트 IP를 식별하기 위해선 해당 IP가 포함된 지역이 어딘지 알 수 있도록 관련 데이터베이스가 필요하다.

$ sudo apt install libnginx-mod-http-geoip geoip-database

이렇게 설치가 완료되면 /usr/share/GeoIP 하위에 GeoIP.bat, GeoIPv6.dat 파일이 생긴다. 이후 nginx.conf를 수정해 해당 파일을 불러와 설정할 수 있다.

load_module "modules/ngx_http_geoip_module.so";

http {
    geoip_country       /usr/share/GeoIP/GeoIP.dat;

    map $geoip_country_code $allowed_country {
        default no;
        KR yes;
    }
    
    ...중략...
    
    server {
        if ($allowed_country = no) {
            return 403;
        }
    }
}

이렇게 필요한 server block 안에 조건을 추가하면 된다.