Nginx에서 특정 IP 접근 금지 시키기 (With Url 문자열 접근 막기)

thumbnail

서비스를 열어두면…

오픈을 하고나면 정말 많은 일들이 생긴다.
도메인 주소를 어떻게 알고 이상한 메일들도 오고, 다양한 방법으로 연락이 온다. -_-;;

그래봤자 넷상이니까?
근데 이제 서비스 접근 로그 또는 nginx에 접근 로그를 보면 대환장 파티다.

128.90.135.254 - - [04/Feb/2023:14:03:43 +0000] "GET / HTTP/1.1" 301 178 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:108.0) Gecko/20100101 Firefox/108.0"
159.223.56.86 - - [04/Feb/2023:14:17:38 +0000] "GET / HTTP/1.1" 301 178 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36"
20.231.80.56 - - [04/Feb/2023:14:24:53 +0000] "GET /wp-login.php HTTP/1.1" 301 178 "-" "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36"
109.237.98.53 - - [04/Feb/2023:14:41:09 +0000] "GET /.env HTTP/1.1" 301 178 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
109.237.98.53 - - [04/Feb/2023:14:41:10 +0000] "POST /.env HTTP/1.1" 301 178 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
109.237.98.53 - - [04/Feb/2023:14:41:10 +0000] "GET /.aws/credentials HTTP/1.1" 301 178 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
109.237.98.53 - - [04/Feb/2023:14:41:11 +0000] "POST /.aws/credentials HTTP/1.1" 301 178 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
109.237.98.53 - - [04/Feb/2023:14:41:12 +0000] "GET /.aws/config HTTP/1.1" 301 178 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
109.237.98.53 - - [04/Feb/2023:14:41:12 +0000] "POST /.aws/config HTTP/1.1" 301 178 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
109.237.98.53 - - [04/Feb/2023:14:41:13 +0000] "GET /aws/credentials HTTP/1.1" 301 178 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
109.237.98.53 - - [04/Feb/2023:14:41:14 +0000] "POST /aws/credentials HTTP/1.1" 301 178 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
109.237.98.53 - - [04/Feb/2023:14:41:14 +0000] "GET /credentials HTTP/1.1" 301 178 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
109.237.98.53 - - [04/Feb/2023:14:41:15 +0000] "POST /credentials HTTP/1.1" 301 178 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
109.237.98.53 - - [04/Feb/2023:14:41:16 +0000] "GET /test.php HTTP/1.1" 301 178 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
109.237.98.53 - - [04/Feb/2023:14:41:16 +0000] "POST /test.php HTTP/1.1" 301 178 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
109.237.98.53 - - [04/Feb/2023:14:41:17 +0000] "GET /laravel/.env HTTP/1.1" 301 178 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
109.237.98.53 - - [04/Feb/2023:14:41:17 +0000] "POST /laravel/.env HTTP/1.1" 301 178 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
109.237.98.53 - - [04/Feb/2023:14:41:18 +0000] "GET /demo/.env HTTP/1.1" 301 178 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
109.237.98.53 - - [04/Feb/2023:14:41:19 +0000] "POST /demo/.env HTTP/1.1" 301 178 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
109.237.98.53 - - [04/Feb/2023:14:41:19 +0000] "GET /web/.env HTTP/1.1" 301 178 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
109.237.98.53 - - [04/Feb/2023:14:41:20 +0000] "POST /web/.env HTTP/1.1" 301 178 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
109.237.98.53 - - [04/Feb/2023:14:41:21 +0000] "GET /phpinfo HTTP/1.1" 301 178 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
109.237.98.53 - - [04/Feb/2023:14:41:21 +0000] "POST /phpinfo HTTP/1.1" 301 178 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.129 Safari/537.36"
178.62.72.53 - - [04/Feb/2023:20:28:52 +0000] "GET / HTTP/1.1" 301 178 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36"
159.223.56.86 - - [04/Feb/2023:23:44:00 +0000] "GET / HTTP/1.1" 301 178 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36"
165.227.89.199 - - [05/Feb/2023:00:23:58 +0000] "GET / HTTP/1.1" 301 178 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36"
159.223.56.86 - - [05/Feb/2023:01:15:39 +0000] "GET / HTTP/1.1" 301 178 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36"
5.62.58.235 - - [05/Feb/2023:02:16:29 +0000] "GET / HTTP/1.1" 301 178 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36"
205.210.31.157 - - [05/Feb/2023:04:08:24 +0000] "GET / HTTP/1.1" 301 178 "-" "Xpanse, a Palo Alto Networks company, indexes customer network perimeters. If you have any questions or concerns, please reach out to: scaninfo@paloaltonetworks.com."

이건 내 Nginx 접근 기록에서 따온 로그 중 일부다.
저기 109.237.98.53IP 접근을 보라.

파이썬이나 기타 언어로 봇 만들어서 취약점을 열심히 찾는…
참 부지런하다…

난 게을러서 저런 노력도 못할 듯 싶다 -_-;;
무튼 서비스가 오픈되면 어떻게들 귀신같이 알고 저렇게 온다.

img01


무튼 예전부터 나는 이걸 보호할 방법을 찾았고 적용했었다.
그리고 포스팅 해야지 하다가..(아마 흑우집합소 1세대쯤이었…)

그래서 이걸 이제야 포스팅 해본다.

How To?

일단 nginx가 설치되어 있다는 것을 가정한다.
nginx의 기본 설정 파일을 vim이던 원하는 편집기로 연다.

보통은 경로가 /etc/nginx/nginx.conf 일거다.
물론 보안을 생각하면 다른 장소로 옮겨둔 사람도 있겠지만…

이 conf파일에 작성해도 좋지만 나 같은 경우 따로 빼뒀다.

http {
    ## Some Config

    ## 별도 경로로 빼둔 설정파일들
	include /home/mymy/nginx/ip-block-list.conf;  #ip block
  	include /home/mymy/nginx/hack_word.conf; #Hack word
  	include /home/mymy/nginx/ip-range-block-list.conf; #ip range block
}

저 설정파일들은 nginx에서 사용할 변수를 만들어 둔 파일들이다.
그리고 저 설정파일들은 아래서 더 자세하게 설명하겠다.


개별 IP 막기

위의 ip-block-list.conf 파일에는 다음과 같이 되어 있다.

geo $bad_ip {
    5.62.41.163 1;
    5.62.58.235 1;
    default 0;
}

상단에 geo를 적고 $표시가 변수 이름이다.
그리고 안에 값은 밴 시킬 ip는 1을 주고, 그 외는 허용하려 하기에 0을 줬다.

여기까지 하고 되면 참 좋겠지만…
이제 몇 가지 설정이 남았다.

다시 nginx.conf 파일을 열거나 자신의 서비스에 맞는 설정을 빼뒀으면 그 config를 열어준다.

server {
  #기본 설정
  listen 80;
  listen [::]:80;
  root /var/www/html;

  server_name bcow.world;

  #Ban black ip
  if ($bad_ip) { return 444; }

  #Ban ip range
  if ($bad_ip_range) { return 444;  }

  #특정 url 패턴을 거부
  if ($bad_word = 1) { return 444; }

  underscores_in_headers    on;  #1. 언더형식의 헤더를 허용 합니다.

  #실제 사용 처리
  location / {
    proxy_set_header Range $saferange;

    proxy_pass http://localhost:11122334;
    proxy_pass_request_headers	on; ## 요청 헤더 바로 전달
  }
}

설정을 저렇게 해주면 된다.
if ($bad_ip) { return 444; } 이 설정으로 인해,
해당 IP는 444응답… 즉 아무 응답도 못받고 죽은 서버라는 응답을 받게 된다.

만약 특정 Ip 영역대를 밴 시키고 싶다면?


IP Class로 막기

IP는 알다시피 A클래스, B클래스, C클래스 영역으로 나눠져있다.
그리고 서브넷 등등…

자세한 건 네트워크 쪽 찾아보거나 시스코의 CCNA 자격증 공부하면 줄기차게 나온다.
무튼…

이번엔 위에서 설명된 ip-range-block-list.conf 설정을 열람해보자

geo $bad_ip_range {
	# A
	103.0.0.0/8 1; #VN-21-11-29
  	185.0.0.0/8 1; #DE-21-12-27

    # B
  	5.161.0.0/16 1; #22-01-02
  	45.83.0.0/16 1; #log4j

    # C
  	77.111.247.0/24 1; #NO-21-12-16
  	167.172.62.0/24 1; #22-01-02

    default 0;
}

얘도 아까 단일 Ip랑 같은 설정을 가진다.
단지 A클래스일 경우 앞 대역 주소를 적고 나머진 0.0.0 즉 해당 네트워크 주소(시작 주소)를 적어둔다.

그리고 뒤에 서브넷을 입력한다.
A클래스니까 당연 서브넷은 8이다.

B랑 C는 A랑 같기에 설명은 생략한다.

img04

무튼 이것도 변수를 선언하고 메인 설정에서 단일 Ip 밴시키듯 아래 설정을 두면 된다.

#Ban ip range
  if ($bad_ip_range) { return 444;  }

근데 이 블록 Ip는 잘보고 막자.
가끔 B클래스가 같은거 같아서 막 막다보면 엄한 영역도 막을 수 있다.

그래서 ip조회 서비스 등을 조회해서 대상 B클래스 주소가 같은 지역 같은 호스트,
비슷한 것 같으면 그 때 막는게 좋다.

img03

이건 IP-API사이트에서 조회한 것인데 저렇게 밑에 hosting이라 되어 있으면 일단 막는게 좋다.
그리고 사진에 나온 것처럼 미국인데 asname이 텐센트…

물론 클라우드를 통해 접근해서 지역은 상관 없긴 하지만…
일단 중국은 다 막자.

다음은 url에 특정 키워드가 포함된 것을 잡는 것을 알아보자.


Url keyword

이것도 원리는 같다.
hack_word.conf 설정 파일을 보자.

#Request Bad Word
map $request_uri $bad_word {
	default 0;
	~*(wp-includes|wlwmanifest|xmlrpc|wordpress|administrator|wp-admin|wp-login|owa|a2billing) 1;
	~*(fgt_lang|flu|stalker_portal|streaming|system_api|exporttool|ecp|vendor|LogService|invoke|phpinfo) 1;
	~*(Autodiscover|console|eval-stdin|staging|magento|demo|rss|root|mifs|git|graphql|sidekiq|c99|GponForm) 1;
	~*(header-rollup-554|fckeditor|ajax|misc|plugins|execute-solution|wp-content|php|telescope) 1;
	~*(idx_config|DS_Store|nginx|wp-json|ads|humans|exec|level|monitoring|configprops|balancer|actuator) 1;
	~*(meta-data|web_shell_cmd|latest|remote|_asterisk|bash|Bind|binding|appxz|bankCheck|GetAllGameCategory) 1;
	~*(exchangerateuserconfig|exchange_article|kline_week|anquan|dns-query|nsepa_setup|java_script|gemini-iptv) 1;
	~*(j_spring_security_check|wps|cgi|asmx|HNAP1|sdk|evox) 1;
	~*(_ignition|alvzpxkr|ALFA_DATA|wp-plain) 1;
	~*(ldap|jndi|dns|securityscan|rmi|ldaps|iiop|corba|nds|nis) 1; # log4j
}

일단 내가 주로 막는 유형만 가져왔다.
저렇게 하면 url에 저 키워드가 들어가면 조건에 걸린다.

내가 집요하게 로그를 분석하며 취약점 찾으려 들어온 놈들 키워드를 분석했다.
이것도 메인 설정에 박아두면 된다.

if ($bad_word = 1) { return 444; }

이렇게 하면 어느정도 취약점 찾는 놈들은 막을 수 있을 것이다.

기타

또 막는 설정은 다양한게 있겠지만…

요새는 영악해서 가짜 UA 달고 오는게 예의지만…
UserAgent 공백으로 오는 무성의한 놈들도 있다. (아주 가끔…)

이런 놈들은 아래 설정으로 막을 수 있다.

#공백 UserAgent 차단
if (\$http_user_agent = "") { return 444; }

그리고 악의적인 행위로 유명한 봇들도 있다.
이건 아래 내용을 참고하자.

#Bot
map $http_user_agent $limit_bots {
        default 0;
        ~*(MJ12bot|ltx71|Adsbot/3.1/WordPress|BLEXBot|UCBrowser|Mb2345Browser) 1;
        ~*(MicroMessenger|LieBaoFast|Headless|netEstate|PetalBot) 1;
        ~*(bingbot|FeedDemon|GrapeshotCrawler|DuckDuckBot|MegaIndex) 1;
        ~*(VelenPublicWebCrawler|SimplePie|YandexBot|SCMGUARD|DotBot) 1;
        ~*(AhrefsBot|SemrushBot) 1;
	~*(wget|curl) 1;
    }

이걸 또 메인 설정(또는 개인 서비스 설정)에 아래와 같이 넣어준다.

#불필요 로봇 차단
if (\$limit_bots = 1) { return 444; }

이렇게하면 일단 가드를 완전히 올린 셋팅은 아니지만 어중이 떠중이는 못들어오게 막아준다.


nginx 책도 빌렸는데 공부를 좀 해서 더 견고하게 막아보도록 노오력해봐야겠다.
아래는 범위 ip 설정을 올려본다.

단일은 진짜 넘 커서…
이건 깃허브나 파일로 제공해야 할 듯 싶다.

해외 서비스 하는 분은 잘 알아보고 적용하고,
국내나 국외 크게 신경 안쓰시는 분은 아래 내용을 참고하자.

geo $bad_ip_range {
	# A
    #34.0.0.0/8 1; #22-07-01 => Google Bot 있을 수 있음
	103.0.0.0/8 1; #VN-21-11-29
  	185.0.0.0/8 1; #DE-21-12-27
	159.0.0.0/8 1; #22-04-17
	20.0.0.0/8 1; #22-04-30
	15.0.0.0/8 1; #22-06-10
	51.0.0.0/8 1; #22-06-27
	35.0.0.0/8 1; #22-07-01

  	# B
    # 66.249.0.0/16 1; #US_21-11-15 => Google Bot 있을 수 있음
  	5.161.0.0/16 1; #22-01-02
  	45.83.0.0/16 1; #log4j
  	51.159.0.0/16 1; #FR-21-11-17
  	137.184.0.0/16 1; #22-01-02
  	167.71.0.0/16 1; #US(NE)-21-11-25
  	185.220.0.0/16 1; #log4j
	20.119.0.0/16 1; #22-02-02
	92.223.0.0/16 1; #22-04-05
	46.101.0.0/16 1; #22-06-09
	163.172.0.0/16 1; #22-06-10
	198.235.0.0/16 1; #22-06-28
	5.62.0.0/16 1;
	178.62.0.0/16 1;
	146.70.0.0/16 1;
	14.116.0.0/16 1;
	144.168.0.0/16 1;
	144.126.0.0/16 1;
	143.198.0.0/16 1;
	128.199.0.0/16 1;
	18.118.0.0/16 1;
	18.234.0.0/16 1;
	159.65.0.0/16 1;
	159.65.0.0/16 1;
	34.240.0.0/16 1;
	157.245.0.0/16 1;
	170.247.0.0/16 1;
	159.223.0.0/16 1;
	165.232.0.0/16 1;
	168.119.0.0/16 1;
	188.166.0.0/16 1;
	198.244.0.0/16 1;
	35.86.0.0/16 1;
	35.89.0.0/16 1;
	106.75.0.0/16 1;
	205.185.0.0/16 1;
	209.141.0.0/16 1;
	209.127.0.0/16 1;
	43.130.0.0/16 1;
	35.93.0.0/16 1;

  	# C
  	77.111.247.0/24 1; #NO-21-12-16
  	167.172.62.0/24 1; #22-01-02
  	171.25.193.0/24 1; #log4j
	92.118.160.0/24 1; #22-04-10
	220.181.51.0/24 1; #22-04-12
	95.142.120.0/24 1; #22-04-25
	5.188.62.0/24 1; #22-05-10
	116.179.33.0/24 1; #22-06-10

	92.223.85.0/24 1;
	93.158.91.0/24 1;
	93.158.90.0/24 1;
	36.99.136.0/24 1;
	111.7.100.0/24 1;
	117.187.173.0/24 1;
	156.146.35.0/24 1;
	185.54.229.0/24 1;
	185.27.99.0/24 1;
	185.181.60.0/24 1;
	198.235.24.0/24 1;
	205.169.39.0/24 1;
	205.210.31.0/24 1;
	208.80.194.0/24 1;
	111.7.100.0/24 1;
	205.210.31.0/24 1;
	51.222.253.0/24 1;
	89.187.163.0/24 1;
	95.142.120.0/24 1;
	42.83.147.0/24 1;
	54.36.148.0/24 1;
	64.43.117.0/24 1;
	191.102.179.0/24 1;
	199.244.88.0/24 1;

  	default 0;
}

Written by@MHLab
Lamborghini Huracan STO / Ferrari 488 Pista
Hardcore life

🫥 Portfolio|  🎲 흑우집합소|  👻 일상 블로그|  📸 Instagram|  💻 GitHub