유성

랜섬웨어 공격 경험 기록: Docker 설정이 만든 보안 구멍 본문

DevOps

랜섬웨어 공격 경험 기록: Docker 설정이 만든 보안 구멍

백엔드 유성 2025. 8. 21. 18:34

자고 일어났더니 서비스 로그인이 되지 않는다..

아침에 일어나 내 서비스의 카카오톡 로그인을 시도했는데 멈춘다. 확인해 보니 데이터베이스가 말끔하게 지워져 있었고, RECOVER DB라는 이름의 데이터베이스 하나만 남아 있었다.

그 안에는 "0.74BTC를 보내면 복구해주겠다." 는 메시지가 들어 있었다.

 

서버 앞에 라우터를 두지 않았고, OS 방화벽은 active 상태였다. 나름 보안에 신경 쓴다고 생각했는데 실제 공격을 당해보니 허술한 부분이 바로 드러났다.

이 글은 그 과정과, Docker의 잘못된 세팅이 만든 보안 취약점을 정리한 기록이다.

공격 증상

  • 카카오톡 로그인 API를 통과한 뒤 모든 기능이 동작하지 않음
  • 서버 로그에는 table이 존재하지 않아 Error 발생 (내가 테이블을 생성 안했다고?)
  • DB에 접속해 보니 테이블 전체 삭제
  • 새로 생긴 DB에 "0.74BTC"를 요구하는 메시지 확인
  • 라우터 없음, OS 방화벽은 active 상태

대응과 복구

다행히 이번 환경은 운영 서비스가 아니라 배포 전 테스트 환경이었다. 지워진 데이터는 다시 만들어도 큰 문제는 없었다. 하지만 향후 운영 환경에서도 같은 상황이 발생할 수 있기에 복구 절차를 밟았다.

  • MySQL binlog 확인 → DROP 명령이 실행된 시점 확인
  • 해당 시점 이전부터 binlog를 순차적으로 replay -> 데이터 복구 완료

 

백업 스냅샷은 없었지만 binlog를 활용해 비교적 빠르게 데이터를 되살릴 수 있었다.

원인 분석

복구 직후 서버를 점검했다. 침투 경로는 Docker의 포트 노출이었다.

  • OS 방화벽은 닫혀 있었지만, Docker는 컨테이너를 띄울 때 iptables 규칙을 직접 수정한다.
  • docker-compose.yml 에 다음과 같은 설정이 있었다.
    ports:
      - "3306:3306"

 

왼쪽 3306(호스트 포트)이 외부에 그대로 열리면서 iptables도 수정되었고, 결국 DB가 외부에 노출됐다.

 

공격자는 무작위 IP를 스캔해 3306 포트가 열린 서버를 찾은 뒤, root 계정으로 무차별 대입(brute-force)을 시도했을 것으로 추정된다.

단순히 ufw status만 보고 안심했던 게 문제였다.

 

피해 범위

운영 환경은 아니었기에 피해는 테스트 데이터 삭제에 그쳤다. 하지만 같은 구조가 운영 서비스에도 있었다면 피해는 상상 이상이었을 것이다.

 


보안 강화

보안 이전 상태

  • 80, 443 포트 : 오픈
  • 22 포트 : iptime 공유기 public ip 기준으로만 접근 가능
  • 3306 포트 : Docker 설정으로 인해 외부 전체 오픈
  • 그 외 포트 : 접근 불가
  • 서버 백신 없음
  • SSH 로그인 : ID/PW 로그인

SSH 보안 강화

  • SSH 포트는 기본 22번 대신 2222번 포트로 변경 (무작위 공격으로 인해 로그가 쌓이는 것을 방지)
  • ID/PW 인증 제거, 비대칭키 기반(pem) 로그인만 허용
  • 문작위 대입 공격을 사실상 불가능하게 만들고, 로그 노이즈도 줄임

비 대칭키의 private key는 네트워크에 절대 노출하지 않도록 하기 위해 Local PC에서 생성한 후 pub 키 만 서버에 올렸다.

MySQL 보안 강화

  • ports: / expose: 설정 제거 (외부 노출 차단)
  • DB 컨테이너는 고정 subnet IP만 할당 (이유는 아래에 더 설명)
  • root 패스워드는 openssl rand -base64 24 로 랜덤 생성
  • 매일 00시에 DB 스냅샷 생성, 원드라이브 또는 NAS에 업로드 예정 (백업 서버와 분리)

OS 보안 강화

  • 우분투 환경에서 ClamAV 설치 후 전체 검사 실행
  • cron 으로 매일 새벽 3시 백신 검사 자동화, 결과 로그만 보관
  • 향후 Slack 알림까지 붙일 예정

 


보안 이후 상태

  • 80, 443 포트 : 오픈
  • 2222 포트 : SSH 통신용, 오픈
  • 그 외 포트 : 접근 불가
  • 일 1회 03시 서버 백신 기동
  • SSH : 비대칭키 로그인만 허용
  • Docker 네트워크 분리 : 리버스 프록시(NGINX)를 DMZ로 두고 다른 서비스는 내부 Docker 네트워크만 사용
  • 00시 서버 내 데이터 스냅샷 생성(백업)

Docker가 iptables을 직접 만지는 걸 고려하지 못한 게 문제였다. 운영 중인 서비스가 아니었기에 망정이지, 실제 서비스 DB였다면 결과는 참혹했을 것이다.

 

서비스를 시작하게되면 꼭 라우터를 추가로 붙여, 2단계 보안을 구성해야겠다.

 


IDE로 DB 접근하기

3306 포트를 열지 않아도, SSH 로컬 포트 포워딩을 통해 접근할 수 있다.

ssh -i key.pem -p 2222 -L 13306:172.30.0.10:3306 user@serverIP

 

로컬에서 localhost:13306 으로 접속하면, 서버 내부 DB와 안전하게 연결된다. (세션은 유지해야 함)

이를 위해 Docker network를 고정 IP로 설정해 두었다.

 


맺음말

랜섬웨어 공격은 남 얘기가 아니었다. 직접 겪고 나니 보안은 서비스 설계 단계부터 가장 먼저 고려해야 할 요소라는 걸 뼈저리게 느꼈다.

 

결론은 간단하다.

포트 하나, 진입점 하나가 서비스 전체를 무너뜨릴 수 있다.