(6/6) 홈페이지 스트레스 테스트 — 보안·가용성과 종합 체크리스트
- 무엇을·왜·어떤 지표로 재는가 — 테스트 종류와 목표 지표
- k6 로 부하·스파이크·소크 돌리기 — 실전 부하 시나리오
- 프론트엔드 성능 — 코어 웹 바이탈과 렌더링 스트레스
- 백엔드·DB 병목 찾기 — 모니터링과 프로파일링
- 복원력 테스트 — 카오스 엔지니어링과 장애 주입
- 보안·가용성 스트레스 — Rate Limit·DDoS·종합 체크리스트 ← 지금 글
Summary
여기까지 왔어요. 부하(2편)도, 렌더링(3편)도, 병목(4편)도, 장애(5편)도 시험했습니다. 그런데 지금까지의 부하는 전부 선의의 사용자를 가정했어요. 마지막으로 남은 건 악의를 가진 부하 입니다. 공격자는 정상 사용자처럼 요청하지 않아요. 한 IP 에서 초당 수천 번을 두드리고, 취약한 입력을 찔러보고, 봇으로 데이터를 긁어갑니다.
이번 편은 이 악의적 부하를 견디는지 시험합니다. Rate Limiting 이 작동하는지, DDoS 완화가 있는지, 흔한 취약점이 부하 상황에서 노출되지 않는지. 그리고 마지막으로 6부작 전체를 하나로 묶는 오픈 전 종합 체크리스트로 시리즈를 마무리할게요.
💡 이 글에서 다루는 것
- 선의의 부하 vs 악의의 부하 — 무엇이 다른가
- Rate Limiting 검증 — 무차별 요청을 막나
- DDoS 완화 — 대량 트래픽 방어 계층
- OWASP ZAP 으로 취약점 스캔
- 6부작 종합 체크리스트 — 오픈 전 최종 점검
1. 악의의 부하는 무엇이 다른가
정상 사용자의 부하와 공격자의 부하는 모양이 달라요. 이 차이를 알아야 방어를 테스트할 수 있습니다.
| 구분 | 선의의 부하 | 악의의 부하 |
|---|---|---|
| 출처 | 여러 사용자에 고루 분산 |
소수 IP 에 집중 또는 봇넷 |
| 패턴 | 사람다운 간격 (생각하는 시간) |
기계적·초고속 |
| 목표 | 정상 기능 사용 | 자원 고갈·데이터 탈취·취약점 공략 |
| 대응 | 확장·최적화 | 차단·격리·필터링 |
핵심은 이거예요. 선의의 부하는 더 잘 처리하는 것이 답이지만(2~4편), 악의의 부하는 처리하지 않고 걸러내는 것이 답입니다. 공격 요청까지 열심히 처리하려 들면 그게 바로 자원 고갈이에요. 그래서 보안 스트레스 테스트는 “잘 막는지”를 확인하는 활동입니다.
2. Rate Limiting — 무차별 요청 막기
가장 기본적인 방어는 Rate Limiting(요청 속도 제한) 이에요. “한 IP(또는 한 계정)가 일정 시간에 보낼 수 있는 요청 수”에 상한을 두는 겁니다. 로그인 무차별 대입, API 남용, 봇 스크래핑을 막는 1차 방어선이에요.
테스트는 간단해요. 정상 상한을 넘겨서 요청을 쏟아붓고, 제대로 차단되는지 봅니다. k6 로 한 IP 에서 빠르게 두드려볼게요.
import http from 'k6/http';
import { check } from 'k6';
export const options = { vus: 20, duration: '10s' };
export default function () {
const res = http.get('https://example.com/api/login');
// 상한을 넘기면 429(Too Many Requests)가 나와야 정상
check(res, {
'차단됨(429)': (r) => r.status === 429,
});
}
여기서 봐야 할 것을 정리하면 이래요.
- 상한 초과 시 429 를 반환하나 — 계속 200 이 나온다면 Rate Limit 이 없는 거예요. 무차별 대입에 무방비입니다.
- 정상 사용자는 안 막히나 — 상한이 너무 빡빡하면 진짜 사용자가 차단돼요. 정상 사용 패턴은 통과해야 합니다.
- 차단이 자원을 아끼나 — 429 응답은 가볍게, 뒷단(DB·비즈니스 로직)까지 안 가고 앞단에서 끊겨야 방어 의미가 있어요.
⚠️ Rate Limit 은 로그인·회원가입·비밀번호 재설정·결제 같은 민감한 엔드포인트에 특히 중요해요. 이런 곳이 무방비면 크리덴셜 스터핑(유출된 비밀번호 대입) 공격의 표적이 됩니다. 엔드포인트별로 다른 상한을 두는 게 좋아요.
3. DDoS 완화 — 대량 트래픽 방어
Rate Limiting 이 “한 출처의 과도한 요청”을 막는다면, DDoS(분산 서비스 거부) 는 수많은 출처(봇넷)에서 동시에 몰아치는 공격이에요. 개별 IP 는 정상처럼 보이는데 합치면 서버를 압도합니다. 이건 애플리케이션 혼자 막기 어렵고, 앞단의 방어 계층이 필요해요.
방어 계층을 정리하면 이렇습니다.
- CDN / DDoS 방어 서비스 — Cloudflare, AWS Shield 같은 서비스가 대량 트래픽을 앞단에서 흡수·필터링해요. 신규 홈페이지도 CDN 앞단을 두는 것만으로 상당한 방어가 됩니다.
- WAF(웹 방화벽) — 알려진 공격 패턴(SQL 인젝션 시도, 비정상 요청)을 규칙으로 차단.
- 자동 확장(오토스케일) — 정상 급증(2편 스파이크)엔 확장으로 대응하되, 공격엔 확장이 아니라 차단으로 대응하도록 구분해야 해요. 공격에 확장으로 맞서면 요금 폭탄만 맞습니다.
🚨 DDoS 부하를 직접 발생시키는 테스트는 매우 조심해야 합니다. 대량 트래픽을 실제로 쏘는 건 자칫 진짜 공격이 되고, 클라우드 사업자 약관 위반이나 법적 문제가 될 수 있어요. 실제 대량 트래픽 시험은 반드시 사업자·방어 서비스와 사전 협의하고 진행하세요. 대부분의 경우는 “방어 계층이 켜져 있는지, 규칙이 올바른지”를 설정 점검으로 확인하는 것으로 충분합니다.
4. 취약점 스캔 — OWASP ZAP
부하 상황에서 보안 취약점이 노출되는 경우도 있어요(에러 메시지에 내부 정보 노출, 부하 시 인증 우회 등). 오픈 전에 자동 취약점 스캐너를 한 번 돌리는 걸 추천드려요. 대표적인 오픈소스가 OWASP ZAP 입니다.
도커로 기본 스캔을 돌리는 게 가장 간단해요.
docker run -t ghcr.io/zaproxy/zaproxy zap-baseline.py -t https://example.com
ZAP 이 사이트를 훑으면서 흔한 취약점을 점검하고 리포트를 냅니다. 나오는 항목은 이런 식이에요.
PASS: 콘텐츠 보안 정책(CSP) 헤더 존재
WARN: X-Content-Type-Options 헤더 누락
WARN: 쿠키에 Secure 플래그 없음
FAIL: 응답에 서버 버전 노출 (Server: nginx/1.24.0)
여기서 나오는 경고는 대부분 헤더 설정이나 쿠키 옵션 같은 것이라 고치기 쉬워요. 가장 흔한 실수는 에러 페이지에 내부 정보(스택 트레이스, DB 오류, 서버 버전)를 그대로 노출하는 것입니다. 스트레스 테스트로 일부러 에러를 유발했을 때(5편의 장애 주입 상황), 에러 화면에 내부 정보가 새지 않는지 꼭 확인하세요. 공격자에게 지도를 그려주는 셈이거든요.
💡 취약점 스캔은 자동 도구가 잡는 “흔한 것”까지예요. 결제·개인정보를 다루는 홈페이지라면, 오픈 전 전문 업체의 모의해킹(침투 테스트)을 별도로 받는 걸 권합니다. 자동 스캐너와 사람의 침투 테스트는 잡는 것이 서로 달라요.
5. 종합 체크리스트 — 오픈 전 최종 점검
6부작 전체를 하나의 체크리스트로 묶었어요. 홈페이지를 오픈하기 전에 이 표를 훑으면서 빈칸을 채워보세요.
| 층 | 점검 항목 | 통과 기준 예시 |
|---|---|---|
| 계획 (1편) | 목표 지표(SLO) 정의 | p95·에러율·목표 RPS 숫자로 명시 |
| 부하 (2편) | 예상 피크의 2배 부하 | 기준 SLO 유지 |
| 부하 (2편) | 스파이크 후 회복 | 급증 뒤 정상 복귀 |
| 부하 (2편) | 소크(수 시간) | 메모리·커넥션 우상향 없음 |
| 프론트 (3편) | 코어 웹 바이탈 | LCP<2.5s, INP<200ms, CLS<0.1 |
| 프론트 (3편) | 저사양·느린망 | 모바일 3G 에서 사용 가능 |
| 백엔드 (4편) | 느린 쿼리·N+1 | 풀스캔·N+1 없음 |
| 백엔드 (4편) | 커넥션 풀 | 고갈·미반납 없음 |
| 복원력 (5편) | 의존성 다운 | 타임아웃·폴백 작동 |
| 복원력 (5편) | 서버 한 대 다운 | 사용자 에러 최소 |
| 보안 (6편) | Rate Limiting | 상한 초과 시 429 |
| 보안 (6편) | DDoS 방어 계층 | CDN·WAF 켜짐 |
| 보안 (6편) | 취약점 스캔 | ZAP 심각 항목 0, 에러 시 내부정보 비노출 |
이 표의 빈칸이 다 채워지면, 처음에 가졌던 “몰리면 안 죽을까?”라는 불안에 숫자로 답할 수 있게 됩니다. 그게 스트레스 테스트의 목적이었어요.
✅ 한 번에 다 하려고 부담 갖지 마세요. 신규 오픈이라면 1편(목표 지표) → 2편 부하·스파이크 → 4편 커넥션 풀 → 6편 Rate Limit 이 네 개만 먼저 해도 실전 사고의 대부분을 막습니다. 나머지는 오픈 후 여유가 생길 때 하나씩 채워가면 돼요.
6. 정리 — 시리즈를 마치며
- 악의의 부하는 잘 처리가 아니라 잘 차단이 정답
- Rate Limiting — 상한 초과 시 429, 정상 사용자는 통과, 앞단에서 끊기
- DDoS 는 CDN·WAF 앞단 계층으로, 직접 부하 발생은 반드시 사전 협의
- OWASP ZAP 으로 흔한 취약점 스캔, 에러 시 내부정보 노출 특히 주의
- 종합 체크리스트로 오픈 전 6개 층을 숫자로 최종 점검
여섯 편에 걸쳐 홈페이지를 여러 방향에서 눌러봤어요. 부하로, 렌더링으로, 병목으로, 장애로, 공격으로. 스트레스 테스트의 진짜 가치는 완벽한 점수가 아니라 “우리 홈페이지의 한계와 약점을 우리가 먼저 안다” 는 자신감이에요. 한계를 알면 그 앞에 여유를 두고, 약점을 알면 미리 방어를 심어둘 수 있으니까요.
이제 배포 버튼을 누를 때 마음 한구석의 불안이, 체크리스트의 초록 체크로 바뀌어 있길 바랍니다.
일단 오늘은 여기까지….. 긴 시리즈 따라와 주셔서 고맙습니다. 단단한 홈페이지 오픈하세요.