UFW 네트워크 방화벽으로 중국 IP 대역 차단


리눅스 | 2019-01-18 15:01 | comments | 16,166 views


안녕하세요.

핀코인입니다.

아래 방법은 Cloudflare 웹 방화벽을 사용하고 있기 때문에 실제로 중국 IP 차단을 하려면 Nginx 또는 Django에서 처리해줘야 합니다.

하지만 웹방화벽을 사용하지 않는다면 여전히 유용한 방법입니다.

1. 중국 IP 차단 계기

중국 IP 대역에서 매번 사이트 취약점은 없는지 스캔하고 계속 악의적 공격을 시도하는 것 때문에 중국 IP 대역을 차단 여부에 대한 고민이 많았습니다. 그래서 문제해결을 위해 고민해본 방안은 두 가지입니다.

  • 한국 IP 대역만 접속 허용
  • 중국 IP 대역만 접속 차단

처음에 한국 IP 대역만 접속 허용하는 것도 생각해봤습니다만 미국, 캐나다, 호주 등등 페이팔 결제 고객을 고려해서 이 조치는 시행하지 않기로 했습니다.

중국 IP의 신뢰가 무너진 이유는 다음과 같습니다.

  • 3자 사기 사건의 초기 접근 시도
  • 중국의 비트코인 외환탈세 혐의자와 상품권 거래 내역 때문에 세무조사
  • Invalid HTTP_HOST header 변조 시도나 SQL 인젝션 같은 끊임 없는 공격 시도
  • 아이디/비밀번호 무작위 대입 Brute Force 공격 시도
  • DDoS 공격 시도

묻지마식으로 들어오는 공격을 일일이 다 대응하기도 힘들고 지쳐서 결국 중국 IP 대역은 차단하기로 결심했습니다.

cloudflare의 국가 차단 기능을 이용해보려고 했으나 Enterprise 플랜에서만 국가 차단 기능을 제공합니다. Enterprise 플랜은 cloudflare와 정해진 가격이 있는 것이 아니라 가격 협의를 해야 합니다. 그래서 직접 UFW 방화벽 차단을 하기로 했습니다.

2. 중국 IP 대역 얻기

IP2LOCATION에서 제공하는 무료 IP 대역 정보 파일을 다운로드 하겠습니다. MaxMind에서 제공하는 GeoLite2 Free IP 데이터베이스도 많이 쓰입니다. 많은 오픈소스가 이 데이터베이스를 기반으로 하는데 IP2LOCATION이 국가별로 CIDR 포맷 다운로드가 더 편리해서 이를 사용하기로 했습니다.

https://www.ip2location.com/free/visitor-blocker

위 페이지에 접속해서 하단에 보면 아래와 같이 국가를 선택하고 CIDR 포맷으로 다운로드 선택합니다. 그리고 IPv4와 IPv6 파일 모두 다운로드 합니다.

2019년 1월 18일 현재 IPv4는 총 6,737개 대역과 8,780개의 대역으로 합산하면 15,517개의 UFW 방화벽 차단 규칙을 추가해야 합니다.

UFW 기초 사용법은 UFW 방화벽 설정으로 리눅스 서버 보안 강화 게시물을 참고합니다.

3. 파이썬 스크립트 작성

cat, grep, awk, sed, xargs 같은 명령어를 잘 쓰던 때라면 bash로 충분히 해결할 수 있지만 다 까먹은 관계로 그냥 파이썬으로 파일을 읽어서 하나씩 규칙을 추가하도록 하겠습니다.

#!/usr/bin/python

import os

cidr_old = ''
cidr_new = 'ipv6-190108.txt'
number = 6743

if cidr_old:
    with open(cidr_old) as f:
        for i, line in enumerate(f, start=1):
            if not line.startswith('#') or not line.strip():
                print('{} = {}'.format(i, line.strip()))
                os.system('ufw delete deny from {} to any'.format(line.strip()))
else:
    print('file not specified')

if cidr_new:
    with open(cidr_new) as f:
        for i, line in enumerate(f, start=1):
            if not line.startswith('#') or not line.strip():
                print('{} = {}'.format(i, line.strip()))
                os.system('ufw insert {} deny from {} to any'.format(number, line.strip()))
else:
  print('file not specified')

위 스크립트에서 주요 변수 설명은 다음과 같습니다.

  • cidr_old: 기존 IP 대역 txt 파일
  • cidr_new: 새로 받은 IP 대역 txt 파일
  • number: 규칙 추가 시 선행 번호 (IPv4: 1, IPv6: 마지막 번호)

cidr_old를 둔 이유는 한 달에 한 번 씩 IP 대역 파일을 업데이트해야 합니다. 새 IP 대역을 추가하기 전에 기존 대역은 모두 제거해야 합니다. 그래서 기존 대역 파일을 지우지 않고 유지합니다. 최초 실행 시에는 기존에 추가된 규칙이 없으니까 빈 문자열로 합니다.

참고로 다음에서 등록한 차단 규칙을 제거하는 명령어는 아래와 비슷한 형태입니다.

ufw delete deny from 1.0.1.0/24 to any

cidr_new는 새로 받은 IP 대역 파일에 따라 모두 차단 규칙을 추가합니다.

number는 방화벽 규칙을 추가할 때 선행하는 번호입니다. 기존에 1, 2, 3 규칙이 있는데 1번 규칙을 추가할 경우 기존 규칙은 2, 3, 4로 밀려나고 해당 규칙이 1번이 됩니다. 그래서 IPv4 방화벽 규칙을 추가할 때는 insert 1으로 적어주면 됩니다.

그래서 다음과 유사한 명령어로 계속 방화벽 차단 규칙을 등록합니다.

ufw insert 1 deny from 1.0.1.0/24 to any

UFW #1368411 버그로도 등록되어 있는데 IPv6 규칙은 IPv4 규칙보다 선행할 수 없습니다.

만약 IPv6 규칙 추가를 위해 insert 1으로 똑같이 명령하면 다음의 에러가 발생합니다.

ERROR: Invalid position '1'

따라서 반드시 끝에 존재하는 IPv6 규칙 번호를 적어줘야 합니다.

예를 들어서 핀코인은 IPv6 허용 룰은 딱 하나 있는 데 바로 Nginx Full (v6)입니다. 이것 빼고는 나머지 다 IPv6 접속 불가합니다.

sudo ufw status numbered
... 생략 ...
[6347] Nginx Full (v6)            ALLOW IN    Anywhere (v6)

위 예시처럼 만약에 IPv4 차단 규칙을 추가하면 위와 같이 마지막 IPv6 규칙 번호 6347를 확인할 수 있습니다. 이들 중에서 가장 첫 번호를 선택하시면 됩니다. IPv6 규칙이 없으면 IPv6 접근을 모두 불허할 수도 있습니다.

어쨌거나 위 예시의 경우에는 IPv4 차단 규칙을 추가할 때는 스크립트의 number 값을 1로 하고 IPv6 차단 규칙을 추가할 때는 스크립트의 number 값을 6347로 지정해야 합니다.

4. 파이썬 스크립트 실행

cidr_old, cidr_new, number 변수값을 올바르게 지정했으면 아래와 같이 명령해서 실행할 수 있습니다.

sudo python3 ban.py

반드시 루트 권한으로 명령어를 실행해야 합니다.

약 1만5천건 모두 삭제 후 추가하는데 4~5시간 정도 소요되므로 이는 서비스 주요 운영 시각은 피하는 게 좋겠습니다.

그런데 이 대역 차단 외에 규칙은 몇 개 안 되니까 그냥 UFW 규칙 초기화 명령어를 쓰는 방법도 고려해볼 만한 것 같습니다.

sudo ufw reset

핀코인은 언제나 고객 여러분이 믿고 이용할 수 있는 서비스 제공을 위해 최선을 다합니다.

대한민국 1등 온라인 상품권 쇼핑몰 핀코인!

감사합니다.


#방화벽 #ufw


Related Posts

blog comments powered by Disqus