1P by GN⁺ | ★ favorite | 댓글 1개
  • TablePlus는 몇 주째 이어진 DDoS 시도에도 IP 차단이나 Cloudflare “Under Attack” 모드 없이 서버 상태를 관찰하고 있음
  • 최근 30일 설치 파일 다운로드 시도는 약 600만 회, 최근 5일만 800,126회였으며 파일 크기는 다운로드당 약 200MB임
  • 공격 중에도 서버 CPU 사용률은 대부분 0~1% 에 머물렀고, 8개가량의 API 서비스와 데이터베이스가 캐시 없이 월 수십억 요청을 처리할 수 있게 구성돼 있음
  • 백엔드는 앱별 모놀리식 서비스로 묶고, Docker·Kubernetes·런타임 환경 없이 단일 바이너리를 새 VPS에 배포하는 방식을 사용함
  • Go/Rust 프레임워크, 데이터베이스 인덱싱, 로그 DB 분리, Nginx 리버스 프록시, Cloudflare CDN/R2, 메일 발송 throttling 같은 단순한 구성이 공격 비용과 운영 복잡도를 낮춤

몇 주간 이어진 DDoS 시도

  • 누군가 TablePlus 서버에 몇 주 동안 수억 건의 요청을 보내고 설치 파일을 수백만 번 다운로드하려고 시도함
  • 설치 파일 다운로드 시도는 최근 5일 동안 800,126회, 최근 30일 기준 약 600만 회에 달함
    • 설치 파일 크기는 다운로드당 약 200MB
  • 최근 30일 API 호출 기준으로 트래픽 대부분은 EU, 특히 Germany와 United Kingdom에서 발생함
    • 이 수치는 다운로드 요청과 CDN 트래픽을 포함하지 않음
  • 글 작성 시점에도 공격은 계속 진행 중임

실제 대응: 차단보다 버티는 구조

  • 공격자 IP 주소를 차단하지 않음
  • Cloudflare를 사용하지만 “Under Attack” 모드는 켜지 않음
  • 공격 중에도 서버 CPU는 대부분 0~1% 수준으로 거의 유휴 상태임
  • 서비스가 월 수십억 요청을 문제없이 처리할 수 있고 비용 부담도 크지 않아 별도 조치를 거의 하지 않음

단순한 백엔드 설계

  • TablePlus 앱 설계는 단순함을 지향하며, 백엔드 서비스도 가능한 한 최소 구성으로 유지함
  • Vercel이나 Netlify 같은 서드파티 렌더링 서비스는 공격 중 병목이나 예상치 못한 청구서를 만들 수 있어 사용하지 않음
  • 자체 웹서버를 쓰면 이런 제한을 피할 수 있다고 봄
  • 과거에는 약한 VPS와 프로세서 때문에 모놀리스가 병목이 될 수 있었지만, 현재 VPS는 멀티코어 CPU, 큰 RAM, 빠른 SSD를 제공함
    • 빠른 SSD와 RAM은 데이터베이스 성능을 크게 높임
    • 올바르게 구현하면 단일 인스턴스의 모놀리스 서비스도 월 수십억 요청을 처리할 수 있음

앱별 모놀리스 운영 방식

  • 각 앱에 필요한 API, 웹사이트, 이메일, 결제 등을 하나의 서비스로 통합함
  • 배포는 설정 파일 하나, 빌드, 배포만으로 끝남
  • 다른 클라우드 벤더로 서비스를 이전하거나 새로 배포할 때 빠르게 처리할 수 있음
  • 의존성이 적어 디버깅과 병목 식별이 쉬움
    • 오류가 발생해도 확인해야 할 서비스가 하나이거나 소수에 그침
  • 선택 가능한 모놀리스 프레임워크 예시는 다음과 같음
    • Golang: Echo, Gin
    • PHP: Laravel
    • Ruby: Rails
    • Rust: Actix, Rocket, Warp

월 수십억 요청을 위한 구성 원칙

  • 고성능 웹 프레임워크를 선택하며, TablePlus는 GolangRust를 선호함
  • 데이터셋이 커질수록 조회 시간을 줄이기 위해 데이터베이스에 인덱스를 설정함
  • 핵심 비즈니스 성능을 보호하기 위해 주 데이터베이스와 로그·사용량 데이터베이스를 분리함
    • 주 데이터베이스는 변하지 않거나 시간이 지나도 크기가 늘지 않는 데이터용
    • 로그·사용량 데이터베이스는 시간이 지나며 계속 커지는 데이터용
  • 핵심 API 앞단에는 리버스 프록시를 두어 요청을 처리하고 분산함
    • 여러 서버가 필요한 경우 도움이 됨
    • TablePlus는 Nginx를 사용함
  • 모든 것을 Cloudflare 뒤에 두고 캐시, Argo, Cloudflare와 서버 간 full SSL을 적절히 설정함
  • DDoS 보호가 있는 CDN을 사용함
    • TablePlus는 비용 절감과 보호를 위해 Amazon CloudFront + S3보다 Cloudflare R2와 CDN을 선호함
  • 큰 다운로드 파일을 CDN이나 캐싱 없이 VPS에 두면 대역폭을 빠르게 소모함
    • TablePlus는 무제한 대역폭의 Cloudflare CDN을 사용함
    • 같은 도메인에서 Argo를 활성화하면 Cloudflare CDN 트래픽이 Argo를 거칠 수 있고, Argo 대역폭은 무료가 아니므로 비용이 커질 수 있음
  • 비밀번호 찾기처럼 서버에서 이메일을 보내야 하는 요청은 throttling으로 메일러를 보호함

배포 방식: 컨테이너 없이 바이너리 실행

  • TablePlus는 Docker, Kubernetes, 컨테이너, 별도 런타임 환경 설정 없이 배포 과정을 최대한 단순하게 유지함
  • 배포 단위는 바이너리
    • Linux 서버에 복사한 뒤 프로세스로 실행함
    • macOS에서 TablePlus 앱을 실행하는 방식과 비슷하게 다룸
  • Linux Systemctl이 프로세스를 감시하고 치명적 오류가 발생하면 재시작하도록 맡길 수 있음
  • VM, 가상화, 서드파티 인프라 관리자 같은 중간 계층에 CPU/RAM을 낭비하지 않기 위해 네이티브 방식으로 실행함
  • Go와 Rust는 고성능 언어이며 배포용 바이너리 파일을 생성할 수 있어 선택함

Vercel 사용 시 켜둘 보호 기능

  • Vercel은 이런 상황에서 사이트를 보호하는 기능으로 Spend ManagementAttack Challenge Mode를 제공함
    • Spend Management: soft 또는 hard 지출 한도를 설정할 수 있음
    • Attack Challenge Mode: Cloudflare의 “Under Attack” 모드와 유사함
  • Vercel을 사용한다면 해당 기능을 켜두는 것이 필요함

댓글과 토론

Hacker News 의견들
  • 이 글은 자화자찬이 너무 심하게 느껴짐. “월 10억 요청”은 초당 몇백 요청에 불과해서 사소한 수준이고, DDoS라고 부르기도 어려움
    게다가 사이트가 CDN인 Cloudflare 뒤에 있는데, 성능 관점에서 뭔가 대단한 일을 했다고 보는 이유가 더 이해되지 않음
    예를 들어 200MB 파일이 CDN에 캐시되어 제공되지 않는 합리적인 상황은 없음. 애플리케이션 서버가 다운로드마다 디스크에서 200MB를 읽고 클라이언트로 복사하지 않는다고 자랑스러워할 일은 아니고, 그렇게 하면 너무 명백히 나쁜 설계임

    • 말하는 200MB 파일https://tableplus.com/download의 TablePlus 클라이언트 앱 다운로드라면, Windows용은 183MB이고 실제로 Cloudflare에 캐시되어 있음

      # curl -v https://files.tableplus.com/windows/5.9.2/TablePlusSetup.exec > /dev/null

      < cache-control: max-age=691200

      < cf-cache-status: HIT

      < age: 2980

    • 보통 이런 건 FAANG 회사라면 개발자 1천 명 이상이 필요하다고 여길 만한 일 아닌가? 큰 회사들도 정기적으로 못 하는 일을 두고 어떻게 자화자찬이라고만 할 수 있는지 모르겠음

    • 초당 몇백 요청으로만 보긴 어려움. 요청 밀도는 시간에 따라 균등하지 않고, 평균의 20배까지도 자주 올라갈 수 있음

  • 4TB는 사실 DDoS 공격이라고 보기 어렵지 않나? 시간당 4TB라면 DDoS라고 할 수 있겠지만, 월 4TB는 초당 1.5MB뿐임
    월 600만 요청도 초당 2요청에 불과함. 이 규모에서는 모놀리스 서비스로 운영한다는 사실이 별로 중요하지 않아 보이고, 특히 Cloudflare가 CDN 캐시로 대부분의 요청을 처리한다고 보면 더 그렇다

    • 웹의 절대다수는 월 5~20달러짜리 다중 입주 호스팅에 올라간 WordPress 사이트이고, 더 큰 조직이면 Drupal인 경우가 많음. 캐시도 설치하지 않고 데이터베이스에 직접 붙어 있어서, 인터넷의 대부분 사이트는 초당 4요청만으로도 다운될 수 있음

      미친 소리처럼 들리겠지만 현실이 그렇다. 예전에 Cloudflare에서 DDoS 방어, WAF, 방화벽, 고객용 보안 프로젝트를 관리했는데, 웹 스크래핑이나 아주 사소하고 낮은 HTTP 요청률만으로 고객 사이트가 내려가는 일을 자주 봤음

      큰 숫자가 헤드라인을 차지하지만, 대부분의 사람이 실제로 체감하는 건 작은 숫자

    • 서비스 거부 공격은 시간당 몇 KB만으로도 가능함. 대상 서비스의 무거운 API 엔드포인트를 건드리면 그것만으로도 서비스를 내릴 수 있고, Distributed는 여러 머신이 동시에 공격한다는 뜻일 뿐임

      DDoS에 반드시 거대한 처리량이 필요한 건 아님. 다만 뉴스에 나오는 건 보통 큰 공격들임

      이런 공격의 목표는 원본 서버의 대역폭 할당량을 태우거나, 대역폭 비용을 감당 못 하게 만드는 것일 수 있음. 단일 또는 소수의 공격 머신으로도 아주 싸게 가능함. 대부분의 데이터센터와 호스팅 업체는 대역폭 제한이 있거나 일정량 이후 과금하는데, 공격받는 회사는 감당 못 할 청구서를 받고 나서야 알아차리는 경우가 너무 많음

    • 전체 플레이어가 50명쯤인 게임 다운로드 웹사이트가 있음. 아무도 안 쓰고, 실제 사람이 게임을 다운로드하는 건 월 몇 번 정도일 것 같음
      그런데 2GB zip 파일 하나에서 지난달 5TB 트래픽이 나왔고, 이게 몇 년째 계속되고 있음. 이건 DDoS가 아니라 링크를 전부 따라가면서 다운로드를 취소하지 못하는 잘못 설정된 봇/크롤러일 뿐임

    • 하루에 1TB 정도인 것 같지만, 그래도 여전히 매우 작은 편임

    • 트래픽이 얼마나 불규칙한지에 달린 듯함

  • 이건 데스크톱 앱을 위한 정적 마케팅 사이트일 뿐임. 토론 포럼도 없고 피드백은 GitHub 이슈로 처리함
    정적 마케팅 사이트 배포가 얼마나 단순한지, 정적 파일이 하루 수백만 번 다운로드되어도 버틴다는 걸 자랑하는 건 꽤 이상함. 그리고 여기서 완화 작업을 하는 건 Cloudflare지 그들이 아님. 이런 조그만 트래픽에 완화가 필요하다면 말이지만

    내가 이런 “공격”을 받았다면 Cloudflare가 매달 보내는 “X TB 전송, 거의 100% 대역폭 절약” 이메일을 받기 전까지는 알아차리지도 못했을 듯함

    앱 자체는 좋아하고 추천할 만함

    • 앱은 나도 좋아하지만, 이 글은 ChatGPT에게 특이한 마케팅 글을 만들어 달라고 한 것처럼 들림. 전체적으로 말이 잘 안 되고, 실제 DDoS 공격을 겪어본 사람에게는 더더욱 그렇다
    • “배포가 얼마나 단순한지 자랑한다”는 점은 오히려 더 많이 나왔으면 함. 사람들이 자기들의 과도하게 복잡한 인프라가 최적이 아니라는 걸 더 알수록 좋음
  • 이건 DDoS 공격이라기보다는, 설명상 월 8TB쯤의 추가 트래픽이 “짜증 나게 무의미한 서비스 남용”에 가까워 보임
    그런 남용이 비용이나 자원 고갈 문제를 만들지 않는 한 무시해도 괜찮지만, “알고 보니 자동 확장 플릿 용량의 80%가 아무 유용한 일도 안 하고 있었다” 같은 이야기는 우울할 정도로 흔하니 최소한 지켜볼 필요는 있음

    이런 남용에서 가장 짜증 나는 부분은 주로 로그임. 로그 대부분이 같은 호스트들이 똑같이 무의미한 행동을 반복하는 내용으로 채워짐. 로그 저장소가 싸고 넉넉하다면 큰 문제는 아니지만, 특정 트래픽을 자동으로 남용으로 분류하고 일상적인 처리를 억제하는 방법은 확실히 좋은 아이디어임

    다만 말처럼 쉽지 않음. 인바운드 SMTP 서버에 노골적이고 어리석은 남용을 잡는 분류 로직을 몇 번이나 추가했는지 셀 수 없는데, 그때마다 경계선상으로는 유효한 시나리오까지 걸리곤 했음

    연속된 토끼굴에 너무 많은 시간을 쓰면 실제 일을 못 하게 되기 쉽다. 그래서 외주를 주거나, 그것도 너무 번거롭거나 비싸면 짜증나더라도 남용을 그냥 무시하는 게 나을 때도 있음

    • AWS에서 8TB 송신 트래픽은 월 1TB 무료분을 감안해도 595달러이고, Hetzner에서는 10달러 미만부터 시작함
      DigitalOcean은 예를 들어 s-4vcpu-8gb-intel에 포함된 5TB 위로 3TB 초과분에 30달러를 내고, Linode는 3TB 초과분이 15달러임. 그래서 글의 요지는 있다고 봄
    • 계속 무시하면 더 수상한 일을 하도록 부추기는 셈임. 그런 태도가 오늘날 인터넷을 거의 늪지대로 만들었음
  • 이건 주목할 만한 “공격”이 아님. 누군가의 머신에서 폭주한 단일 bash 스크립트만으로도 가능함
    “영국에서 월 5천만 요청”은 평균 초당 20요청도 안 됨. 단일 Go 서버 하나가 큰 최적화 없이도 그 250배 요청량은 처리할 거라고 기대함

    조언 자체가 꼭 나쁜 건 아니지만, 그 숫자들이 조언의 증거가 되지는 않음. Go HTTP API 서비스라면 작은~중간 VPS에서 데이터베이스 작업과 JSON 포매팅이 조금 있어도 최적화 없이 초당 5천 요청은 처리한다고 기대함. 하루 수십억 요청을 받고 피크에는 초당 50만 요청을 넘던 곳에서 비슷한 서비스를 수십 개 배포해 본 경험에 근거한 수치임

    • 그런 트래픽이 API에 반복 요청으로 몰리는데 전부 수상하지 않은 위치에서 온다면, DDoS가 아니라 클라이언트 코드에 무한 재시도 루프를 실수로 넣었는지부터 생각해야 함
  • 이게 피해를 주지 않는 건 좋지만, 이걸 조언으로 받아들이기에는 빠진 부분이 많아서 좀 불안함
    Docker보다 바이너리 배포를 선호하자는 건 괜찮지만, 그 바이너리가 도는 호스트는 어떻게 할 건가? 컨테이너를 쓰는 이유 중 하나는 보안 강화 설정을 배포에 함께 묶어서, 나중에 확장해야 할 때도 노드 간 보안 설정이 동일하다는 확신을 얻기 위해서임

    여기서 말하는 모놀리스는 단일 VPS에 올릴 수 있고, 그건 좋고 싸기도 함. 하지만 크래시가 나거나 하드웨어가 어떤 이유로든 고장 나면 꽤 큰 다운타임이 생길 수 있음

    또 하나 걱정되는 건 모든 걸 모놀리스에 묶으면 애플리케이션 스택의 심층 방어를 잃는다는 점임. 누군가 프런트엔드를 통해 앱을 뚫으면 백엔드 데이터 저장소까지 곧장 갈 수 있음. 그래서 많은 사람이 데이터 저장소를 내부 웹 서비스 뒤에 두고, 프런트엔드에서 떨어진 사설 네트워크의 보안 그룹으로 막아 공격 표면을 브라우저로 수행할 수 있는 동작 수준으로 제한함

    • 공격 표면을 늘려서 보안이 좋아지는 세계는 없음

    • Docker를 설치한다고 호스트가 보안 처리된다고 생각한다면 그건 틀림. 확장할 때 추가 호스트는 어떻게 설정할 건가?

      Docker를 쓰면 컨테이너뿐 아니라 호스트, 즉 컨테이너를 실행하는 서비스까지 안전해야 함. 확장해서 호스트를 추가 배포할 때도 똑같이 안전해야 함

      코드형 인프라와 코드형 설정을 쓴다면, 시스템 설정 뒤에 바이너리를 배포하든 Docker를 배포하든 본질적으로 다르지 않음

    • “베어메탈” 설정을 어느 정도 재현 가능하게 만드는 도구들이 있음. 예를 들면 NixOS, Ansible, Amazon AMI 이미지 빌드가 있음

    • “프런트엔드를 통해 앱을 뚫는다”는 말이 늘 이해가 안 됨. SQL 삽입은 원격 코드 실행 없이 데이터 저장소를 직접 건드리고, XSS는 다른 사용자에게 수평적으로 영향을 줌
      그런데 프런트엔드에서 전체 백엔드까지 자유롭게 어떻게 도달한다는 건가? 사람들이 Go API 서비스 안에 셸 접근 권한이 있는 JavaScript 인터프리터를 돌리고 사용자 입력에 eval을 호출하는 건가? 기술적으로 너무 억지스럽게 느껴짐

    • 결국 모호함을 통한 보안 아닌가? 너무 복잡하게 만들어서 우리도 이해 못 하면 남도 이해 못 할 거라는 식인가?

      중요한 건 벽을 더 많이 만드는 게 아니라 벽을 부술 수 없게 만드는 것임. 인터페이스는 성능을 낮추고 복잡도를 올림

  • 개인적으로 거슬리는 표현임. “월 10억 요청”은 대략 초당 370요청임. 잘 설정된 서버 한 대로도 처리 가능할 수준이고, 확실히 10대 미만이면 됨
    단일 악성 bash 스크립트 하나로도 그 정도 트래픽은 만들 수 있음

    • 마이크로서비스 덕분에 우리는 초당 1000요청을 처리하려고 Kubernetes 노드 45개가 필요함
    • 그 요청들이 시간상 균등하게 분포한다면 그렇다. 하지만 공격 상황에서는 요청이 갑자기 치솟은 뒤 평평해질 수 있고, 그래도 30일 기준으로는 월 10억 요청이 될 수 있음
    • 잘 설정된 서버 한 대가 아니라, JVM JIT가 작동한 뒤라면 코어 하나로도 가능함
  • 현실 감각이 떨어진 건지도 모르겠지만, 월 수십억 요청은 별것 아닌 것처럼 들림. 이게 큰 DDoS 공격으로 간주되나?

    • 누가 비용을 내느냐에 달림. 직접 호스팅이면 문제가 아니지만, 서버리스에서는 그런 수준도 보통 비용이 많이 들고, 특히 가치 없는 트래픽이면 더 그렇다
    • 합리적으로 설계된 API라면 초당 300~400 API 요청은 무거운 부하가 아님. 초당 300~400 정적 파일 요청은 땅콩보다도 작은 수준임
    • 맞음. 월 10억 요청은 평균 초당 380요청이라 그렇게 높지 않음
    • 여러 요인에 달림. 보통 인프라는 예상 사용량에 맞춰 프로비저닝하고, 과도한 여유분은 낭비임
  • “각 앱마다 배포와 유지보수가 쉬운 모놀리스 서비스를 만든다. Docker도, Kubernetes도, 의존성도, 런타임 환경도 없이 새로 만든 VPS 어디에나 배포할 수 있는 바이너리 파일 하나뿐”이라는 부분은 좋았음

    • TablePlus를 직접 쓰지는 않음. 이게 마케팅 웹사이트 얘기라면 Kubernetes가 필요 없다는 건 당연함
      애플리케이션 얘기라면 의존성이 없다는 게 의아함. 데이터를 저장하고 로그도 남기지 않나?

    • 이건 Golang의 정말 훌륭한 장점임. VPS를 띄우고 합리적인 기본값을 적용한 뒤, 교차 컴파일해서 바이너리를 실행하면 됨

      Python, Node, PHP 배포와 비교하면 불필요한 복잡도가 훨씬 적음

      데이터베이스 서버를 실행하고 계속 살려두는 것도 이렇게 단순할 수 있다면 좋을 텐데

  • 제목을 보고는 좀 더 swole doge에 어울리는 내용을 기대했음. 조언의 상당 부분에는 동의하지만, Cloudflare 뒤에 있다는 건 결코 아무것도 아님
    트래픽 분포에 따라서는 Cloudflare 없이 VPS만으로도 잘 버텼을 수 있고, 규모도 그렇게 커 보이지 않음. 초당 요청 수와 Cloudflare가 원본 도달 전에 얼마나 막았는지 같은 더 자세한 통계를 보면 흥미로웠을 것임

    내가 아는 스웨덴 기업 대상 러시아발 7계층 DDoS는 주요 제공자들이 용량 문제에 부딪혀 쓰러질 정도로 컸음. Verizon, Azure Frontdoor, Cloudflare, GCP 로드 밸런서까지 포함됨. 그런 규모를 상대로는 이 전략이 절대 통하지 않음