본문 바로가기

생활코딩

라즈베리파이 - nginx - 특정 국가 접속 차단

일전에 ModSecurity를 사용하여 보안을 강화할 때 IP 주소들을 좀 살펴보니 공격의 출처는 대부분 - 아니 모두가 외국이었습니다. 그래서, 특정 국가들에 대해서 좀 차단을 해야겠다는 생각에 nginx에 설정을 추가했습니다.

 

geoip-database

특정 국가의 요청을 차단하려면 요청이 들어온 쪽의 IP 주소가 어느 국가인지를 알아야 합니다. 이런걸 IP 주소를 가지고 위치 정보를 확인한다고 GeoIP라고 부릅니다. 또, 리눅스 배포본에 포함된 IP 기반 위치 정보 C 라이브러리의 이름도 GeoIP입니다. 

국가별 IP 주소 대역은 이런 에서 쉽게 확인 가능하지만, 이를 데이터베이스화 하여 사용할 수 있게 하는 건, 또 다른 문제입니다. 거기다가 nginx에 바로 연동되게 하려면 많은 시간과 노력이 필요할겁니다. 그런데, 고맙게도 geoip-database라는 GeoIP 데이터가 데비안 리눅스 패키지에 포함돼 있고, 이를 nginx에서 사용할 수 있습니다.

패키지에 대한 설명은 https://screenshots.debian.net/package/geoip-database 에서 확인할 수 있고, GeoIP 데이터베이스에 대한 설명은 https://mailfud.org/geoip-legacy/ 여기에 잘 나와 있습니다.

GeoIP 데이터는 기존의 버전이 지원 중단되고 GeoIP2 넘어간 듯 합니다. 그런데, 아직 많은 리눅스 배포 본들이 GeoIP를 유지하고 있어서 https://mailfud.org/geoip-legacy/ 여기에서 계속 업데이를 하고 있는 듯 하고요.
GeoIP2는 https://www.maxmind.com/en/geoip-databases 여기에서는 상용으로 판매하는 듯 하고, https://db-ip.com/db/lite.php 에서는 CC by 4.0 하에 배포하는 버전과 상용 버전을 가지고 있습니다. CC by 4.0 라이선스 버전을 사용하는 경우 하단데 제공처를 표시하는 의무가 있으니 dp-ip 사이트에서 Licensing Terms 부분 꼭 읽어 보시면 좋습니다.
nginx의 경우 상용 버전인 ngix plus에서만 GeoIP2 모듈을 지원하고 오픈 소스 버전은 기본적으로 GeoIP 모듈만 존재합니다. nginx 오픈 소스 버전에 GeoIP2를 사용하려면 https://github.com/leev/ngx_http_geoip2_module 같은 모듈을 직접 빌드해서 사용해야 합니다.

설치

geoip-database와  nginx의 ngx_http_geoip_module을 설치합니다.

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

 

이렇게 설치하게 되면 GeoIP 데이터베이스 파일은 /usr/share/GeoIP 에 다음과 같이 추가되게 됩니다.

 

GeoIP 데이터 베이서는 위에서처럼 apt-get으로 설치해도 되고, https://mailfud.org/geoip-legacy/ 여기서 최근 버전을 받아 /usr/share/GeoIP 위치에 복사해 놓고 사용해도 됩니다.

설정

http {
    ##
	# GeoIP
	##
    # 필수 설정 입니다. GeoIP 데이터베이스를 지정합니다.
	geoip_country         /usr/share/GeoIP/GeoIP.dat;

    # nginx로 요청이 들어오면 국가 코드가 $geoip_country_code에 담기는데
    # 특정 값일 때는 #allowed_country를 0으로 설정하고, 기본적으로는 1로 설정합니다.
    # 이 값을 가지고 0인 경우에는 차단하는 설정을 할 것입니다.
	map $geoip_country_code $allowed_country {
            default      1;   # 기본값은 허용
            "DE"         0;
            "CN"         0;
            "HK"         0;
    }

    # 로그에 국가 코드를 찍기 위해 로그 포맷을 geo라는 이름으로 하나 추가했습니다.
    # 마지막에 "$geoip_country_code" 부분이 국가 코드입니다.
	log_format geo '$remote_addr - $remote_user [$time_local] '
                           '"$request" $status $body_bytes_sent '
                           '"$http_referer" "$http_user_agent" "$geoip_country_code"';
}

차단 설정

server {
	# 이 부분은 차단과 상관 없고, 앞서 설정한 로그 형식을 access 로그에 적용하는 것입니다.
    access_log /var/log/nginx/access.log geo;

    location / {
        # 차단 설정
        if ($allowed_country == 0) {
            return 403;
        }
    }
}

 

재기동 및 테스트

nginx를 재기동하면 적용이 됩니다.

sudo systemctl restart nginx

 

테스트 하는 간단한 방법은 위에 설정 부분에서 default 를 1로 지정하지 않고 0으로 지정한 후에 재기동 해 보는 것입니다. 그리고, 나서 로컬 접속해 보면 403응답을 받는 것을 알 수 있습니다.

만약, 외부 망에 연결된 상태에서는 "KR"을 0으로 추가해 놓고 재시작 한 후에 스마트폰에서 셀룰러망 상태에서 연결해 보면 바로 확인 가능합니다.

 

데이터베이스 업데이트

https://mailfud.org/geoip-legacy/ 에 업데이트 파일이 올라옵니다. 2024년 10월 19일 최근 업데이트인 걸 보면 꾸준히 업데이트 하는 듯 합니다. 여기서 파일을 다운로드 받아서 /usr/share/GeoIP 위치에 기존 파일을 덮어 쓰고 nginx를 재시작하면 됩니다.

 

참고