서버 보안은 특정 도구 하나를 설치하는 일이 아니라 노출 범위를 줄이고, 권한을 제한하고, 사고를 발견하고 복구할 수 있게 만드는 과정이다. 아래 체크리스트는 일반적인 웹 서비스의 운영 환경을 기준으로 정리했다.
중요도: 🔴 필수 · 🟡 강력 권장 · 🔵 환경에 따라 적용
1. 네트워크 경계
- 🔴 인바운드와 아웃바운드 정책을 모두 정의하고 필요한 통신만 허용한다.
- 🔴 MySQL, Redis, MongoDB 포트는 인터넷에 공개하지 않고 사설망 또는 로컬 인터페이스에서만 접근하게 한다.
- 🔴 웹 트래픽은 원칙적으로 80과 443만 공개한다. 80은 HTTPS 전환 용도로만 사용한다.
- 🔴 SSH는 전 세계에 열어두기보다 관리 IP, VPN, Bastion Host, Cloudflare Access 같은 관리 경로로 제한한다.
- 🟡 웹/API와 데이터베이스를 네트워크 및 계정 수준에서 분리한다.
- 🟡 클라우드 보안 그룹과 호스트 방화벽을 함께 확인한다.
아웃바운드도 중요하다. 서버가 침해됐을 때 임의의 외부 주소로 데이터가 빠져나가지 않도록 애플리케이션이 실제로 사용하는 목적지만 허용하는 것이 이상적이다.
2. SSH 접근
- 🔴
PermitRootLogin no로 Root 직접 로그인을 막는다. - 🔴 공개키 인증을 사용하고 가능하면 비밀번호 로그인을 끈다.
- 🔴 개인별 계정과
sudo를 사용하고, 퇴사·역할 변경 시 접근 권한을 즉시 회수한다. - 🟡 반복 로그인 실패는 Fail2Ban, 클라우드 방화벽 또는 접근 프록시로 차단한다.
- 🟡 SSH 키에는 암호를 설정하고 주기적으로 교체한다.
- 🔵 포트 변경은 스캔 로그를 줄일 수 있지만 본질적인 보안 통제는 아니다.
3. HTTPS와 TLS
- 🔴 유효한 인증서를 적용하고 자동 갱신 실패를 모니터링한다.
- 🔴 HTTP 요청을 HTTPS로 리다이렉트한다.
- 🔴 오래된 TLS와 취약한 암호군을 비활성화한다. 실제 지원 범위는 사용하는 프록시와 클라이언트를 기준으로 점검한다.
- 🟡 HTTPS 구성이 안정된 뒤 HSTS를 단계적으로 적용한다.
- 🟡 쿠키에는
Secure,HttpOnly, 적절한SameSite속성을 사용한다.
HSTS의 includeSubDomains와 preload는 모든 하위 도메인이 HTTPS를 제공할 때만 활성화해야 한다. 잘못 적용하면 하위 서비스에 접근하지 못할 수 있다.
4. Nginx 또는 Apache
- 🟡 서버 버전과 불필요한 응답 헤더를 숨긴다.
- 🔴 요청 본문과 업로드 크기를 서비스 요구사항에 맞게 제한한다.
- 🔴 요청 속도와 동시 연결을 제한하되 프록시 환경의 실제 클라이언트 IP 처리를 먼저 확인한다.
- 🔴 헤더·본문·업스트림·유휴 연결 timeout을 설정한다.
- 🔴 허용하지 않는 HTTP 메서드와 관리용 경로를 차단한다.
- 🟡 보안 헤더를 적용하고 애플리케이션의 CSP 호환성을 테스트한다.
5. API 경계
- 🔴 서버에서 모든 입력의 타입, 길이, 범위, 형식을 검증한다.
- 🔴 사용자와 API 키별 Rate Limit을 적용한다. 로그인과 비밀번호 재설정에는 더 엄격한 정책을 둔다.
- 🔴 인증 후에도 객체와 행위 단위의 권한을 검사한다.
- 🔴 에러 응답에 Stack Trace, SQL, 내부 경로, 비밀정보를 노출하지 않는다.
- 🟡 프레임워크에 맞는 보안 헤더 미들웨어를 사용한다. Express 계열이라면 Helmet을 고려할 수 있다.
- 🟡 CORS 허용 Origin, Method, Header를 최소화한다.
- 🟡 파일은 크기·실제 콘텐츠·MIME·확장자를 함께 검사하고 웹 루트 밖에 임의 이름으로 저장한다.
CORS는 브라우저의 교차 출처 읽기를 제어할 뿐 인증이나 서버 접근 통제를 대신하지 않는다.
6. 인증과 세션
- 🔴 Access Token은 짧게 유지하고 Audience, Issuer, 만료, 서명을 모두 검증한다.
- 🔴 Refresh Token은 서버에서 폐기할 수 있는 구조로 관리한다. Redis, DB의 해시 저장, 세션 저장소 등 시스템에 맞는 방식을 선택한다.
- 🔴 로그아웃·비밀번호 변경·계정 잠금 시 관련 세션을 폐기한다.
- 🟡 Refresh Token Rotation과 재사용 탐지를 적용한다.
- 🟡 MFA, 중요 작업 재인증, 로그인 알림을 위험도에 맞게 추가한다.
7. 비밀번호
- 🔴 Argon2id를 우선 고려하고, 호환성이 필요하면 적절한 비용의 bcrypt를 사용한다.
- 🔴 SHA-256 같은 빠른 범용 해시만으로 비밀번호를 저장하지 않는다.
- 🔴 사용자마다 고유 Salt를 사용한다. 라이브러리가 안전하게 생성하도록 맡기는 편이 좋다.
- 🟡 충분히 긴 비밀번호와 비밀번호 관리자 사용을 허용한다.
- 🟡 유출된 비밀번호 차단과 로그인 시도 제한을 적용한다.
8. 데이터베이스
- 🔴 애플리케이션에서 Root나 관리자 계정을 사용하지 않는다.
- 🔴 서비스와 환경별 계정을 만들고 필요한 스키마·명령 권한만 부여한다.
- 🔴 외부 포트를 닫고 사설망 접근을 강제한다.
- 🔴 백업을 암호화하고 실제 복구 훈련으로 복원 가능성을 확인한다.
- 🟡 DB 연결에도 TLS를 적용하고 인증정보를 주기적으로 교체한다.
- 🟡 감사 로그와 비정상 쿼리·접속 알림을 구성한다.
9. 비밀정보와 운영
- 🔴
.env와 인증서·키 파일을 Git에 커밋하지 않는다. - 🔴 JWT Secret, DB 비밀번호, API Key는 배포 플랫폼의 Secret Store에서 주입한다.
- 🔴 로그에 토큰, 비밀번호, 쿠키, 개인정보가 기록되지 않도록 마스킹한다.
- 🔴 OS·컨테이너·런타임·라이브러리의 보안 업데이트를 지속적으로 적용한다.
- 🟡 Git 이력과 이미지 레이어까지 Secret Scan을 수행한다.
- 🟡 Prometheus, Loki, Grafana 등 관측 도구 자체의 인증과 외부 노출도 점검한다.
- 🟡 장애 대응 절차, 담당자, 키 폐기와 복구 순서를 문서화한다.
배포 전 최소 확인 목록
- 공개 포트와 관리 접근 경로를 확인했다.
- DB와 관측 도구가 인터넷에 노출되지 않았다.
- Root 로그인과 비밀번호 SSH를 제한했다.
- HTTPS, 인증서 자동 갱신, 보안 헤더를 확인했다.
- 인증·권한·입력 검증·Rate Limit 테스트를 완료했다.
- Secret Scan과 의존성 취약점 검사를 통과했다.
- 백업을 실제로 복원해봤다.
- 로그와 알림으로 침해 징후를 발견할 수 있다.
참고 자료
이 목록은 출발점이다. 결제, 의료, 공공, 개인정보 처리 시스템은 위협 모델과 관련 법규를 별도로 검토해야 한다.