보안 기준선
개요
전체 참조는 references/baseline.md에 있습니다(§0–§18 섹션, ## N.으로 검색). 이 파일은 운영 절차입니다. 핵심 원칙: 위협 등급에 맞춰 엄격함을 조정하고, 각 발견 사항을 증거로 입증하십시오. 세 가지 법칙: 클라이언트를 절대 신뢰하지 말고, 모델 코드를 절대 신뢰하지 말고, 기본값을 절대 신뢰하지 마십시오.
모드 선택
| 요청 | 모드 | baseline.md에서 읽을 내용 |
|---|---|---|
| "안전하게 프로젝트 계획/시작", 에이전트 규칙 작성 | 계획 | §0, §2, §3, §16 |
| "이 앱/리포지토리/PR 검토/감사" | 코드 검토 | §1.3, §4–§11, §15.2 |
| "내 서버/홈랩/VPS 감사", "최신 상태인가요?" | 호스트 감사 | §3.3, §8.3, §12, §13 |
| "해킹당함/키가 유출됨" | 사고 대응 | §17, §8.2 |
호스트 감사에는 계정이나 개인 데이터를 보유하는 각 인터넷 연결 앱에 대한 간단한 코드 검토가 포함됩니다.
1단계 — 등급 분류(항상 먼저 수행, 보고서에 명시)
소유자가 부르는 이름이 아닌 관찰 가능한 사실로 결정하십시오:
| 등급 | 조건 | 적용 |
|---|---|---|
| T0 장난감 | 실제 사용자나 데이터가 없음 AND 인터넷에서 접근 불가(LAN 전용, 또는 SSO 뒤에 있음) | §2, §8 |
| T1 공개, 계정 없음 | 인터넷 접근 가능, 로그인 없음, 개인 데이터 저장 없음 | T0 + §9, §10 |
| T2 계정/사용자 데이터 | 로그인 있음, 개인 데이터(이름, 이메일, 게스트 목록) 저장, 보유한 API 키 또는 토큰 | 모든 것 |
| T3 대규모 금전/PII/규제 대상 | 결제, 건강, 자격 증명 저장소, 금융, 1천 명 이상의 데이터, 클라이언트 계약 | T2 + 외부 검토 + §14 |
홈랩 호스트는 실행 중인 가장 높은 등급으로 평가됩니다. 자격 증명 수집기(비밀번호 관리자, n8n, Home Assistant, Portainer, docker.sock 보유자)는 폭발 반경으로 인해 T3입니다.
2단계 — 증거 수집(읽기 전용)
번들된 스크립트를 bash를 통해 실행하십시오. 원격 호스트에서는 SSH를 통해 스트리밍하십시오: ssh host 'bash -s -- --remote-digests' < scripts/audit-docker-host.sh 및 ssh host 'bash -s -- <project-dir>' < scripts/scan-code.sh.
bash scripts/audit-docker-host.sh --remote-digests— OS 패치, 재부팅 플래그, 수신 소켓, 방화벽, sshd, 모든 컨테이너의 사용자/권한/공개 포트/docker.sock, 비밀처럼 보이는 환경 변수 이름, 이미지 최신 상태(UP-TO-DATE / OUTDATED / local-build).bash scripts/scan-code.sh <project-dir>— 비밀, 주입, XSS, 대량 할당, 클라이언트 제공 테넌트 ID, 실패 시 공개 처리, 약한 암호화, 잠금 파일, Dockerfile/컴포즈 위험, 경로 인벤토리에 대한 grep 리드.
그런 다음 스크립트로 할 수 없는 작업을 수행하십시오:
- 리버스 프록시 인벤토리: 모든 공개 호스트 이름, 대상, 그리고 앞에 인증이 있는지 여부(NPM DB / Caddy / Traefik 레이블)를 나열하십시오. SSO/액세스 목록 없이 공개 호스트 이름에 있는 관리 UI(§3.3 목록) = 발견 사항.
- 외부 보기: LAN 외부 경로에서
curl -sI https://<host>로 헤더(§10.2)를 확인하고/.env,/.git/config,/admin,/api를 GET으로만 조사하십시오. - 각 T2+ 앱에 대한 권한 부여 추적: 모든 경로에 대해 인증 검사 이름과 주체/테넌트 ID가 어디에서 오는지 명시하십시오(§4.3). §1.3 질문을 적용하십시오.
- 프록시 신뢰: 앱이
X-Forwarded-For를 읽는 경우, 신뢰하는 홉을 확인하십시오($proxy_add_x_forwarded_for는 추가함; 첫 번째 값은 공격자가 제어함). - 역할별 자격 증명 강도: 모든 역할(관리자, 직원, 자원봉사자, API/MCP 토큰)에 대해 시드를 포함하여 비밀이 설정되는 방법, 일반 길이 검사를 우회하는 레거시 및 마이그레이션 경로를 찾으십시오.
.env값의 실제 길이를awk -F= '{print $1, length($2)}'로 확인하고 절대 출력으로 인쇄하지 마십시오. 약한 비밀과 우회 가능한 속도 제한은 두 개가 아닌 하나의 발견 사항입니다. - 버전 대 권고 사항: 각 인터넷 연결 앱에 대해 실행 중인 버전을 최신 릴리스 및 알려진 CVE와 비교하십시오. 제품의 보안 권고 사항을 웹 검색하십시오.
호스트 게이트(§16 체크리스트는 프로젝트별로 적용됨, 호스트에는 이것을 사용하십시오)
- 모든 공개 호스트 이름이 나열되었고, 각 관리 UI(§3.3)에는 SSO, 액세스 목록 또는 VPN이 앞에 있거나 공개되지 않음
- 하이퍼바이저, Docker, NPM/프록시 관리자, 비밀번호 관리자 관리: 절대 공개되지 않음
- 필요하지 않은 모든 자체 호스팅 앱에서 공개 가입 비활성화(Vaultwarden, Open WebUI, Gitea, Immich 등)
- WAN 접근 가능 포트 = 80/443만(+VPN). Docker 게시 포트는 ufw를 우회함: 라우터 포워드 및
DOCKER-USER확인 - 프록시가 앱이 속을 수 없는 클라이언트 IP를 전달함(§4.5, X-Forwarded-For)
- docker 그룹 구성원 나열됨, 각각은 root와 동일한 권한
- 비밀 파일 모드 600, 세계에서 읽을 수 있는
.env/키 없음 - OS 패치됨, 7일보다 오래된 보류 재부팅 없음; 이미지 최신(최신 상태 표)
- 백업이 최근에 실행되었고 복원 테스트됨(§13.4)
참여 규칙
- 기본적으로 읽기 전용. 쓰기, 재시작, 업데이트, 데이터를 변경하는 POST, 무차별 대입, 또는 소유자가 소유하지 않은 호스트 스캔 금지.
- 비밀 값을 절대 출력하지 마십시오. 변수 이름과 파일:줄만 보고하십시오.
- 구성 저장소(DB 구성 테이블, JSON 설정,
docker inspect환경)는 키와 길이만 검사하십시오:jq 'paths',SELECT key FROM …,awk -F= '{print $1, length($2)}'. 전체 구성 행이나 파일을 보기 위해 덤프하지 마십시오. API 키가 포함될 수 있습니다. - 변경 사항(업데이트, chmod, 구성 수정)은 보고서 이후에만, 그리고 요청자가 요청한 경우에만 이루어집니다. 업데이트는 아래 "안전한 업데이트"를 따르십시오.
3단계 — 보고(이 정확한 형식)
- 범위 및 등급: 검토된 대상, 등급, 한 줄 이유.
- 판결: 한 문장 — 출시 / 수정 우선 / 중지.
- 발견 사항, 심각도 치명적 → 낮음 순위. 각 발견 사항에는: 제목,
CONFIRMED(재현했거나 정확한 코드/구성 경로를 읽음) 또는LEAD(그럴듯하지만 입증되지 않음), 증거(파일:줄, 명령어 + 출력 일부), 한 문장 영향, 수정 방법. - 최신 상태 표(호스트 감사): 구성 요소, 실행 버전, 최신 버전, 업데이트 위험.
- 적용 범위: 확인한 §16 게이트 섹션과 확인하지 않은 섹션 및 그 이유. 침묵은 통과가 아닙니다.
- 다음 조치, 번호 지정, 가장 적은 노력-가장 높은 위험 순.
안전한 업데이트("모든 것이 최신 상태인지 확인")
- 백업이 존재하고 최근인지 확인(§13.4). 각 컨테이너의 현재 이미지 ID를 기록하여 롤백이
image: <repo>@<old digest>가 되도록 하십시오. - 무상태 = 앱이 쓰는 명명된 볼륨이나 바인드 마운트가 없고, 데이터베이스도 없음. 정적 nginx 사이트, gotenberg, flaresolverr는 무상태입니다. 확실하지 않으면 데이터 보유로 취급하십시오.
- 분류: 데이터 보유 또는 스키마 마이그레이션(데이터베이스, Immich, Paperless, Vaultwarden, Firefly, n8n, Home Assistant) → 한 번에 하나씩, 먼저 릴리스 노트에서 주요 변경 사항을 읽으십시오. 무상태(nginx 정적 사이트, 도구) → 일괄 처리.
docker pull을 통해 데이터베이스 주 버전(예: postgres 15→17)을 절대 건너뛰지 마십시오. 덤프/복원이 필요합니다.- 프로젝트별로
docker compose pull && docker compose up -d를 실행한 다음 상태 확인: 컨테이너 상태, 오류 로그, 공개 URL에 대한 HTTP 확인. - 로컬 빌드(
local-build)는--pull로 다시 빌드하여 업데이트합니다. OS 패키지는 sudo가 필요함; sudo가 없으면 목록과 재부팅 플래그를 보고하십시오. - 가져오기가
429 toomanyrequests로 실패하면 중지하십시오. 호스트에docker login을 요청하거나 6시간 후에 다시 시도하십시오. 반복하지 마십시오.
일반적인 실수
| 실수 | 올바른 방법 |
|---|---|
| 모든 것을 "높음"으로 보고 | 심각도 = 악용 가능성 × 등급 × 폭발 반경 |
| 스크립트 적중을 발견 사항으로 처리 | 코드를 읽을 때까지 스크립트 출력은 LEAD입니다 |
| 확인 없이 "컨테이너가 root로 실행됨" | 많은 이미지가 진입점에서 권한을 낮춥니다. 내부 ps를 확인하십시오 |
| LAN 호스트에서 "포트 9000이 열려 있음" | 누가 접근할 수 있는지 말하십시오: LAN 전용, 라우터 포워드를 통한 WAN, 또는 프록시를 통해 |
| 등급을 건너뛰고 정적 사이트를 은행처럼 감사 | 등급 우선; T1은 헤더와 종속성이 필요하며 RLS가 아닙니다 |
:latest로 모든 것을 한 번에 업데이트 | 한 번에 하나의 데이터 보유 서비스, 롤백 다이제스트 포함 |
제어를 비활성화하여 수정(RLS 해제, CORS *) | 정책을 수정하고 절대 제거하지 마십시오(§7.2) |