DEV Community

바람의평온
바람의평온

Posted on

분산형 SSH 공격, fail2ban recidive로 막아낸 이야기

분산형 SSH 공격, fail2ban recidive로 막아낸 이야기

언제부터인가 서버에 잊을만하면 SSH 경고 메일이 계속 들어왔습니다. 분명 fail2ban이 잘 돌고 있고, SSH 포트도 기본이 아닌 다른 걸로 바꿔뒀는데도 말이죠. 첫 아이 키우면서 뭘 해도 처음인 아빠 마음처럼, 서버 운영도 늘 새로운 문제투성이네요. 이번엔 잊을만하면 찾아오는 SSH 무차별 대입 공격에 제대로 대처한 경험을 기록해봅니다. 특히 일반적인 SSH jail로는 잡기 어려운 '분산형 공격'에 어떻게 대응했는지 이야기해보려고 해요. 기존의 fail2ban 설정으로는 반복적인 공격이 막히지 않아 고민이 많았는데, 결국 recidive jail의 설정을 바꿔서 효과적으로 대응할 수 있었습니다.

여기서 확인할 것

  • fail2ban recidive jail의 작동 원리를 이해합니다.
  • 분산형 SSH 무차별 대입 공격의 특징을 알아봅니다.
  • recidive jail 설정을 변경하여 장기적인 공격을 차단하는 방법을 배웁니다.
  • jail.local 파일을 이용한 fail2ban 설정 변경 방법을 확인합니다.
  • 통신사 동적 IP 환경에서 오탐을 줄이며 방어하는 노하우를 공유합니다.

이상하게 계속되던 SSH 로그인 시도들

처음엔 fail2ban이 잘 막아주고 있다고 생각했습니다. SSH 포트도 기본이 아닌 다른 걸로 바꿔뒀고, fail2ban SSH jail도 당연히 켜 놨었거든요. 그런데 어느 날부터인가 서버 로그를 보면 잊을만하면 SSH 로그인 시도들이 계속 눈에 띄는 겁니다. 보통 이런 공격들은 특정 IP에서 여러 번 시도하다가 밴(ban) 당하고 잠잠해지는 게 일반적이었는데, 이건 마치 꼬리 자르듯 IP를 계속 바꿔가며 들어오는 느낌이 들었어요. 공격이 들어오는 IP들을 자세히 살펴보니, 대부분 국내 통신사의 동적 IP 대역을 쓰는 것 같더군요.
처음에는 '내 서버가 유명해졌나?' 하고 잠시 어깨를 으쓱하기도 했지만, 이내 '이러다 정말 뚫리면 어쩌지' 하는 불안감이 더 커졌습니다. fail2ban의 상태를 확인해보니, 개별 SSH jail은 열심히 IP들을 차단하고 있었지만, 어딘가 허술한 느낌을 지울 수 없었습니다. 이상한 건, 재범(recidive) 격리, 그러니까 여러 번 밴당한 IP를 장기적으로 막는 jail은 한 번도 발동한 적이 없다는 사실이었습니다. 이건 뭔가 잘못되어가고 있다는 신호 같았어요.

재범 격리(recidive)가 조용했던 이유

왜 recidive jail이 침묵하고 있었을까 고민이 많았습니다. 제가 찾아본 바로는, fail2ban의 recidive jail은 '이미 여러 번 다른 jail에서 차단당한 이력이 있는 IP'를 대상으로 더 길게 차단해서 반복 공격을 막는 상위 방어 개념이었습니다. 그런데 저희 서버에 들어오는 공격 패턴은 일반적인 recidive jail의 기본 설정과는 좀 달랐던 거죠.
공격자들은 한 IP에서 로그인 시도를 5번 이상 하지 않고, 2~3번 정도 시도하다가 IP를 바꾸는 방식으로 계속 들어오더군요. fail2ban의 기본 SSH jail 설정은 보통 5회 시도에 1일 관찰 기간(findtime)을 가지는데, 공격자들이 교묘하게 이 임계치를 피해서 공격을 하는 겁니다. 예를 들어, 한 IP에서 3번 시도하고 다른 IP로 바꾸는 식으로 분산해서 공격하니, 개별 IP는 밴당하기 전에 이미 사라지거나, 다시 나타나더라도 '재범'으로 인식될 만큼 충분히 많은 이력을 쌓지 못했던 거죠. 결국, recidive jail이 발동할 조건 자체가 충족되지 않았던 겁니다. 이건 마치 넓은 창으로만 세상을 보다가 정작 코앞의 작은 변화를 놓친 기분이었어요.

분산형 공격에 맞춘 recidive 강화 설정

이 문제를 해결하기 위해 가장 중요하다고 생각한 부분은 recidive jail의 설정을 현실적인 공격 패턴에 맞추는 것이었습니다. 단기적인 시도 횟수보다는 '장기적으로 이 IP가 꾸준히 공격을 시도했는가'를 봐야 한다고 판단했죠. 그래서 recidive jail의 findtime(관찰 기간)을 30일로, maxretry(그 기간 안에 밴당해야 하는 횟수)를 3회로 강화했습니다. 즉, 30일이라는 긴 시간 동안 3번만 밴 이력이 생기면 무조건 장기 차단하겠다는 의미였습니다.
설정은 /etc/fail2ban/jail.local 파일의 [recidive] 섹션에 추가하거나 수정해야 합니다. 저도 처음엔 jail.conf를 건드리는 건가 했는데, jail.local이 jail.conf를 덮어쓰는 방식이더군요. 그래서 꼭 jail.local에 반영하는 것이 중요했습니다.

[recidive]
enabled = true
findtime = 30d ; 30일 관찰 창
maxretry = 3 ; 그 안에 3번 밴당하면 장기 격리
bantime = 1w ; (환경에 맞춰 조정)

위 코드는 recidive jail을 활성화하고, 30일 동안 3번 이상 차단된 IP를 일주일간 장기 차단하도록 설정하는 내용입니다. 이렇게 설정하고 나니 왠지 모르게 마음이 좀 놓이는 기분이 들었습니다.

강화된 방어막, 실제 작동 확인하기

설정을 바꾸고 나서 가장 궁금했던 건 '과연 이게 실제로 작동할까?' 였습니다. 단순히 설정만 바꿨다고 끝나는 게 아니니까요. 저는 fail2ban-client 명령어를 통해 recidive jail의 상태를 주기적으로 확인했습니다. 처음엔 여전히 'Currently banned'가 0이었지만, 며칠이 지나자 비로소 숫자가 늘어나기 시작하더군요.

fail2ban-client status recidive # Currently banned 가 0에서 늘어나는지

이 명령어를 입력했을 때, 이전에 항상 0이던 Currently banned 항목에 숫자가 표시되는 것을 보고 정말 안심했습니다. 드디어 이 끈질긴 분산 공격자들이 재범으로 분류되어 장기 격리되기 시작한 것이죠. 동시에 혹시나 정상적인 사용자가 통신사 동적 IP를 할당받아 오탐으로 차단되는 일은 없는지 로그를 주시했습니다. 다행히 제가 관찰한 기간 동안에는 그런 문제는 발생하지 않았습니다. 통신사 동적 IP를 무작정 대량으로 차단하는 대신, 재범 기준을 강화하는 방식으로 접근한 것이 오탐을 줄이는 데 도움이 된 것 같네요.

마치며

이번에 겪은 fail2ban recidive jail 튜닝 경험은 '보통 이렇다'고 알려진 기본 설정만으로는 모든 공격 패턴에 대응하기 어렵다는 걸 다시 한번 깨닫게 해주었습니다. 특히 통신사 동적 IP를 활용하는 분산형 공격은 단기적인 임계치로는 잡기 어렵다는 것을 알게 되었네요. 혹시 여러분의 서버에도 끈질기게 들어오는 SSH 공격이 있다면, recidive jail의 findtime을 길게, maxretry를 현실적으로 조정해보는 것을 추천합니다. 그리고 무엇보다 중요한 건, 설정을 바꾼 후에는 반드시 실제로 작동하는지, 그리고 예상치 못한 부작용은 없는지 꼼꼼히 확인하는 과정이라고 생각합니다.

Top comments (0)