디렉토리 스캔 공격을 막자(NGINX+Fail2ban)

Alex·2024년 12월 19일
1

Plaything

목록 보기
52/118

서버에서 발생하는 500에러를 디스코드 웹훅으로 보내는 기능을 구현했더니
갑자기 메시지 여러개가 들어왔다.

클라이언트 개발자분들께 관련 내용을 물어보니
본인들이 한 게 아니라고 하셨다.



api url들을 보면 인증이나 중요한 정보를 가져가려는 시도로 보인다.
찾아보니 디렉토리 스캔 공격이라고 한다.

우선, SSH는 내 IP에만 열어주자

EC2 보안 그룹을 보니 SSH를 모두 오픈해 놓은 상태였다. 이걸 내 IP로만 우선 제한했다.

이렇게 하면 아마존 콘솔로는 접속이 안됐는데 개인 ssh로 접속을 해야 한다. ip는 네트워크에 따라 변동되니 그때마다 ip를 변경해야 한다고 한다.

디렉토리 스캔을 막아보자.

방법으로는 AWS에서 제공하는 WAF 방화벽과 엔진엑스를 통한 설정이 있다. WAF는 비용이 들어가는 탓에 지금 사용하기에는 부담스럽다.

Fail2ban와 NGINX로 BOT으로 의심되는 IP를 동적으로 차단할 수 있다고 한다.

Fail2ban는 시스템 로그 파일을 모니터링해서 오류나 실패한 시도를 찾고서, 그런 시도를 한 IP주소를 차단한다.

우선, NGINX를 설정해보자.

NGINX를 설정하자.

NGINX와 웹소켓 연결하는 방법은 여기에 정리해두었다.

이제 NGINX의 rate limting 기능을 사용해야 한다.

그 내용이 좀 길어져서 새로운 포스팅으로 정리했다.

NGINX Rate Limiting 기능을 정교하게 사용해보자 여기서 확인 가능하다.

배포서버에서 진행해보자

이제 배포서버에 NGINX를 설치하고 설정파일을 변경하자
NGINX 설정파일은 보통 etc/nginx에 있다.

  • 참고로 엔진엑스에서 upstream을 쓸 때 ip를 쓰면 http://를 지워줘야 한다
  • 설정파일을 수정할 때는 sudo(루트의 권한을 빌려 특정 명령어를 수행) nano로 해야 한다.
(명령어 모음)
sudo systemctl stop nginx(엔진엑스 중지)
sudo systemctl start nginx
sudo systemctl status nginx
sudo apt install -y fail2ban 

/etc/fail2ban/fail2ban.conf

그리고

[nginx-limit-req]
[nginx-banroute]
enabled  = true
filter   = nginx-limit-req
logpath  = /var/log/nginx/access.log
maxretry = 1
findtime = 600
bantime  = -1
action   = iptables-multiport[name=NoNginx, port="http,https", protocol=tcp

이 내용을 추가해준다.

# /etc/fail2ban/jail.d/defaults-debian.conf

[sshd]
enabled = false
sudo service fail2ban start

-->sudo를 안 붙이면 비밀번호를 입력하라고 계속 뜬다.

그리고 이제 NGINX 필터를 만들어야 한다.

cd /etc/fail2ban/filter.d/nginx-limit-req.conf:

[Definition]
failregex = limiting requests, excess:.* by zone.*client: <HOST>
ignoreregex =
sudo service fail2ban restart

테스트를 진행해보자

sudo systemctl stop fail2ban
sudo rm -rf /var/run/fail2ban/*
sudo systemctl start fail2ban

sudo systemctl status fail2ban //fail2ban 상태보기
sudo fail2ban-client status nginx-limit-req //필터 상태보기

그런데 테스트를 진행해도 ip가 차단되지 않았다.

sudo fail2ban-regex /var/log/nginx/error.log /etc/fail2ban/filter.d/nginx-limit-req.conf

스웨거와 관련된 로그만 잡힌다

[Definition]
failregex = ^<HOST> .* "GET .* HTTP/1\.1" 429 .*$
ignoreregex =

sudo fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/nginx-limit-req.conf//테스트

이렇게 내가 맞춰놓은 429 에러를 잡도록 필터를 변경해야 한다.

드디어 ip가 제대로 차단된 걸 확인할 수 있다...!

sudo fail2ban-client unban IP주소

이걸 통해서 ip주소 차단을 해제할 수 있다.

좀더 세밀하게 정책을 짜보자


//jail.conf

findtime = 10
maxretry = 3
# 영구 차단
bantime = -1

우선 10초안에 3번 이상 걸리면 영구차단하는 걸로 초기 보안을 잡아놨다.

//nginx.conf
limit_req_zone $binary_remote_addr zone=error_limit:10m rate=1r/s;

1초에 한번만 허용하는 zone을 만들고

# 일반 HTTP API용
location / {
   limit_req zone=mylimit burst=10 nodelay;
   limit_req_status 429;
   proxy_pass http://wsbackend;
   proxy_set_header Host $host;
   proxy_set_header X-Real-IP $remote_addr;

   # 에러 처리 추가
   error_page 404 = @handle_404;
   error_page 500 502 503 504 = @handle_server_error;
}

location @handle_404 {
   limit_req zone=abuse_limit burst=2 nodelay;
   limit_req_status 429;
   return 404;
}

location @handle_server_error {
   limit_req zone=error_limit burst=2 nodelay;
   limit_req_status 429;
   return 500;
}

이렇게 설정을 바꿔주었다.
우선, 404페이지와 500번대 에러 페이지에 대한 처리를 만들었다.
404인경우 rate limit를 초과하면 429로 그렇지 않으면 404로, 500번대 에러도 마찬가지로 rate limit을 초과하지 않으면 500으로 내보낸다.

[Definition]
failregex = ^<HOST> .* "(GET|POST|PUT|DELETE|HEAD).* HTTP/1\.[01]" (429|404|500) .*$
ignoreregex =

그리고 이렇게 필터링을 해준다.
bot이 계속 새벽마다 와서 이렇게 엄격하게 처리하고 추후에 느슨하게 해도 될듯하다.

새벽에 잠시 자고 왔더니 차단된 ip만 7개다...
계속 어뷰징을 하려고 하나보다

profile
답을 찾기 위해서 노력하는 사람

0개의 댓글