Community코딩 & 개발github.com

보안 앱 스캐폴더 (Secure App Scaffolder)

ANSSI, CIS, FBI, OWASP ASVS 수준 2를 준수하는 안전한 웹 애플리케이션을 시작, 스캐폴딩 또는 재설계할 때 사용합니다. TypeScript 프론트엔드, Python 백엔드, 강화된 PostgreSQL 스택을 생성합니다.

보안 앱 스캐폴더 (Secure App Scaffolder)란 무엇인가요?

이 스킬은 ANSSI, CIS, FBI, OWASP ASVS 수준 2와 같은 업계 표준을 준수하는 '보안 우선 설계' 웹 애플리케이션의 시작점을 생성합니다. 주요 기능으로는 루트리스 컨테이너, 제로 트러스트 입력 검증, 객체 수준 권한 부여, 열 수준 암호화, 멱등적 쓰기, OIDC/LDAPS/WebAuthn 인증, 변조 방지 감사 로그, 허니토큰, 서명된 이미지, 이중 스캐닝(Trivy + OpenSCAP) 등이 포함됩니다. 또한 사전 프로덕션 정리 절차를 제공하여 보안 위험을 최소화합니다. 이 스킬은 코드 생성 시 보안 규칙이 다른 모든 편의성 또는 사용자 경험 규칙보다 우선하도록 설계되었습니다. Docker 및 루트리스 Podman 배포를 지원하며 Kubernetes와 같은 오케스트레이터 매니페스트는 생성하지 않습니다.

지원 대상~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/SkouedLabs/SkouedSkills/tree/HEAD/.claude/skills/secure-app-scaffolder

Installed? Explore more 코딩 & 개발 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

즐겨 사용하는 AI에게 물어보기

이 에이전트 스킬이 미리 로드된 새 채팅을 엽니다.

문서

Secure App Scaffolder

ANSSI, CIS, FBI 및 OWASP ASVS 수준 2를 준수하는 보안 우선 설계 애플리케이션을 생성합니다: TypeScript 프론트엔드, Python 백엔드, 강화된 PostgreSQL.

레이아웃, README 및 UI는 project-blueprint 스킬을 따릅니다. 이 스킬의 보안 규칙은 모든 편의성 또는 UX 규칙보다 우선합니다.

참조 파일 (일치하는 아티팩트를 생성할 때 읽음)

사용 시기

  • 새로운 웹 애플리케이션이나 서비스를 시작, 스캐폴딩 또는 설계할 때.
  • ANSSI, CIS, FBI, OWASP, 강화, 루트리스, 규정 준수를 언급하는 요청.
  • 인증, 권한 부여, 파일 업로드, 감사 로깅, 관리자 기능, 배포 파일 또는 MCP 엔드포인트를 추가할 때.

배포 대상: Docker 및 루트리스 Podman만 해당합니다. 사용자가 명시적으로 요청하지 않는 한 Kubernetes, Helm 또는 기타 오케스트레이터 매니페스트를 생성하지 마십시오.

0. 위협 모델

  • docs/security/threat-model.md (최대 1페이지) 생성: 자산, 신뢰 경계, 행위자, 주요 위험 (STRIDE) 및 각 위험을 완화하는 통제. 업로드, 웹훅, LLM, MCP와 같은 새로운 신뢰 경계가 나타나면 이를 업데이트합니다.

1. 컨테이너 및 런타임

  • 루트리스: 모든 이미지는 웹 서버(nginxinc/nginx-unprivileged, 포트 > 1024)를 포함하여 숫자 USER(예: USER 10001:10001)로 끝납니다.
  • 최소, 고정된 이미지: 다중 단계 빌드; 런타임 단계는 셸, 컴파일러 또는 패키지 관리자가 없는 distroless 또는 slim 이미지이며, 개발 종속성은 제외됩니다. 베이스 이미지는 다이제스트로 고정됩니다. 최신 안정적인 Python.
  • 강화: read_only, 쓰기 가능한 경로에 tmpfs, cap_drop: [ALL], no-new-privileges, 런타임 기본 seccomp 프로필(절대 unconfined 안 됨), pids_limit, 메모리 제한, 상태 확인, 코어 덤프 비활성화(ulimits: core: 0). 오직 리버스 프록시만 포트를 게시합니다. 데이터베이스 네트워크는 internal: true입니다. Docker/Podman 소켓을 마운트하지 마십시오.
  • 하위 프로세스 없음: subprocess, os.system, shell=True를 사용하지 않습니다. 적용 방법: 이미지 내 셸 없음, SAST 규칙, 그리고 각 워커가 시작된 후 로드되는 execve/execveat를 거부하는 인프로세스 seccomp 필터 (컨테이너 수준 거부는 엔트리포인트 자체가 시작되는 것을 방지할 수 있습니다).
  • 최초 실행 보장: 깨끗한 클론에서 docker compose up (docker-compose up 및 podman compose up도 포함)이 처음 시도에 작동합니다: .env 없음, 수동 단계 없음, 컨테이너 엔진 외에 다른 전제 조건 없음. 이미지는 자동으로 빌드됩니다(build:). Docker Compose v2 및 podman-compose에서 지원하는 Compose Specification 기능만 사용합니다. 리포지토리 외부의 호스트 경로 없음, 게시된 포트는 > 1024, CPU 제한 없음(많은 루트리스 cgroup 설정에서 사용 불가). make up은 동일한 명령어의 간소화된 래퍼입니다.
  • 하드코딩된 비밀 없음: 일회성 init 서비스가 명명된 볼륨(0600)에 비밀을 생성하며, 프로덕션에서는 *_FILE 변수를 통해 사용됩니다. 비밀은 환경 변수가 아닌 파일에서 읽습니다.
  • 에어갭 환경: 모든 JS/CSS/글꼴/아이콘은 번들링됩니다. CDN, 런타임 다운로드 또는 텔레메트리가 없습니다. 종속성은 오프라인 빌드 시 내부 미러(Nexus, Artifactory, devpi, Verdaccio)에서 가져옵니다.
  • Vault 준비: 단일 시크릿 제공자 추상화(file 기본값, 프로덕션에서는 vault/sops).
  • 내부 TLS: 백엔드 ↔ 데이터베이스는 TLS를 통해 통신합니다. 서비스 간 선택적 mTLS.

2. 공급망 및 스캐닝

  • 잠긴 종속성: 락파일 커밋; npm ci, uv sync --frozen 또는 pip install --require-hashes 사용. .npmrc에 ignore-scripts=true 설정 (패키지가 설치 스크립트를 필요로 하고 허용 목록에 있는 경우 제외).
  • 빌드 전 게이트: npm audit --audit-level=high 및 pip-audit는 종료 코드 > 0인 경우 빌드를 실패하게 합니다.
  • SAST 및 시크릿: ruff, bandit/semgrep, eslint (+ eslint-plugin-security), gitleaks를 사용한 사전 커밋.
  • 이미지 스캔 (make scan): trivy image (CVE + 시크릿 + 오설정), Dockerfile 및 compose에 대한 trivy config, 베이스 OS의 CIS 프로필에 대한 oscap-podman (또는 oscap-docker).
  • SBOM 및 서명 (make sbom): CycloneDX SBOM (Trivy 또는 Syft 사용), cosign으로 이미지 서명 (오프라인을 위한 키 기반), SBOM을 증명으로 첨부; 배포 시 서명 확인.
  • DAST (선택 사항, 권장): CI에서 실행 중인 스택에 대한 OWASP ZAP 베이스라인.
  • 업데이트: 정해진 주기로 Renovate/Dependabot (또는 동등한 오프라인 검토) 사용.

3. 프론트엔드 (TypeScript)

  • 위치: /frontend 디렉토리, 자체 Dockerfile을 가지며, 권한이 없는 Nginx가 제공하는 정적 자산으로 빌드됩니다.
  • CSP 호환 코드: 인라인 <script> 없음, eval/new Function 없음, 논스 없이 <style>을 주입하는 런타임 CSS-in-JS 없음. 컴파일된 CSS 선호. Trusted Types 활성화 (require-trusted-types-for 'script').
  • 제로 트러스트 입력: 폼별로 타입이 지정된 Zod 스키마를 사용하며, API 유형과 공유됩니다. 신뢰할 수 없는 데이터에 dangerouslySetInnerHTML/v-html을 절대 사용하지 않음. 리치 텍스트가 불가피한 경우 DOMPurify 사용.
  • 멱등성: API 클라이언트는 모든 POST/PUT/PATCH/DELETE 요청에 Idempotency-Key (UUIDv4)를 첨부하며, 사용자 작업당 한 번 생성되고 재시도 시 재사용됩니다.
  • CSRF: 사용자 정의 헤더 (X-Requested-With) + CSRF 토큰; 백엔드도 Origin/Sec-Fetch-Site를 확인합니다. CORS 허용 목록만 사용, 자격 증명과 함께 * 절대 사용 안 함.
  • 오픈 리다이렉트: 로그인 후 next/returnUrl은 단일 /로 시작하는 상대 경로만 허용합니다.
  • 번들에 시크릿 없음; 프로덕션에 소스 맵 없음; localStorage/sessionStorage에 민감한 데이터 없음.

4. 백엔드 (Python) 및 데이터베이스

  • 유효성 검사: 모든 본문, 쿼리 매개변수, 경로 매개변수 및 헤더는 Pydantic으로 최대 길이와 extra="forbid"를 사용하여 검증됩니다 (대량 할당 방지: role, owner_id, is_admin은 입력에서 절대 바인딩될 수 없음).
  • 리소스 제한: 최대 요청 본문 크기, 최대 JSON 깊이/배열 길이, 최대 페이지 크기 (예: 100), 서버측 시간 제한. 사용자 입력의 정규식은 경계가 있거나 ReDoS를 피하기 위해 선형 시간 엔진(re2)을 사용합니다.
  • 안전한 구문 분석: pickle, marshal, yaml.load (yaml.safe_load 사용), eval 없음. XML은 defusedxml을 통해 처리합니다. 템플릿 소스에 사용자 입력 없음 (SSTI). 파일 경로는 확인되고 기본 디렉토리와 비교됩니다 (경로 탐색).
  • 멱등성 저장소: (user_id, key) -> request_hash, status, response, 24시간 TTL. 동일한 키 + 동일한 해시는 저장된 응답을 반환합니다. 다른 해시는 422를 반환합니다. 이는 중복을 방지합니다. 재생 방지는 TLS, CSRF 토큰 및 짧은 세션을 통해 제공됩니다.
  • SQL: ORM 또는 매개변수화된 쿼리만 사용; 동적 식별자 (ORDER BY, 열 이름)는 허용 목록을 통해 처리합니다.
  • 열 수준 암호화: PII는 AES-256-GCM으로 애플리케이션에서 암호화되며, 봉투 암호화(시크릿 제공자의 마스터 키로 래핑된 레코드별 DEK), 키 순환을 위한 key_version 열, 검색 가능한 필드를 위한 HMAC-SHA256 블라인드 인덱스를 사용합니다. 마스터 키는 DB 또는 DB 백업에 절대 저장되지 않습니다.
  • 데이터베이스 강화: 최소 PostgreSQL, scram-sha-256, TLS, 두 개의 역할 (마이그레이션 소유자, 런타임 DML 전용), 앱에서 슈퍼유저 없음, Alembic 마이그레이션, 런타임 역할에 statement_timeout.
  • SQL 콘솔 (있는 경우): 읽기 전용 역할, 단일 SELECT, statement_timeout, 행 제한, 잠긴 구성.
  • 암호화 및 포스트퀀텀: 저장 데이터의 AES-256-GCM은 양자 저항성이 있습니다. PQ 준비는 키 교환 및 서명을 대상으로 합니다. 프록시에서 하이브리드 TLS X25519MLKEM768; ML-KEM/ML-DSA (FIPS 203/204)는 라이브러리가 지원하는 경우에만 사용합니다. 랜덤 값은 secrets/crypto.getRandomValues에서 가져옵니다. 암호화 기본 요소를 직접 구현하지 마십시오.
  • 아웃바운드 요청 (SSRF): UI에서 구성 가능한 모든 URL (웹훅, syslog, LLM, OIDC)은 검증됩니다: https만 허용 (명시적 허용 목록이 없는 경우), 확인된 IP가 루프백/링크-로컬/메타데이터 (169.254.0.0/16, fd00:ec2::254) 또는 비공개인 경우 거부 (허용 목록에 없는 경우), DNS 확인 후 재확인 (DNS 리바인딩), 교차 호스트 리다이렉트 없음, 엄격한 시간 제한.
  • 아웃바운드 웹훅: HMAC-SHA256 (X-Signature + 타임스탬프)으로 서명되어 수신자가 확인할 수 있습니다.
  • 이메일: 헤더 값에서 CR/LF 제거; 인증서 확인이 포함된 SMTPS.
  • 내보내기: =, +, -, @, 탭 또는 CR로 시작하는 CSV/XLSX 셀은 ' 접두사가 추가됩니다 (수식 삽입).
  • 속도 제한: 로그인, 비밀번호 재설정, MFA 확인, API 키, 내보내기, 업로드 및 고비용 엔드포인트.
  • 응답: 인증된 API 응답에 Cache-Control: no-store. request_id가 포함된 일반 오류 메시지; 스택 추적은 로그에만 있습니다. OpenAPI UI는 프로덕션에서 비활성화되거나 관리자 전용입니다.

5. 권한 부여

  • 기본적으로 거부: 모든 경로는 필요한 권한을 선언합니다. 선언이 없는 경로는 시작 또는 테스트 시 실패합니다.
  • RBAC 역할을 코드에서 직접 확인하지 않고 권한에 매핑된 역할을 사용합니다.
  • 객체 수준 검사 (IDOR/BOLA): ID로 모든 읽기/쓰기에 대해 리포지토리 계층에서 소유권 또는 테넌트 확인을 수행합니다. 기존 객체에 대한 무단 액세스는 404를 반환합니다.
  • 기능 수준 검사: /api/v1/admin/* 아래의 관리자 경로는 단일 종속성으로 보호되며, UI만 숨기는 방식으로 절대 보호되지 않습니다.
  • 민감한 작업 (역할 변경, 키 생성, 내보내기, 사용자 삭제)은 최근 재인증이 필요합니다. 관리자로의 역할 승격에는 선택적 4-눈 승인이 필요합니다.

6. 파일 업로드 (있는 경우)

  • 프록시 및 앱 수준에서 크기 제한; 확장자 허용 목록 및 매직 바이트 검사.
  • 웹 루트 외부 (또는 객체 스토리지)에 저장, 임의 파일 이름, Content-Disposition: attachment 및 X-Content-Type-Options: nosniff와 함께 제공.
  • 이미지 재인코딩 (EXIF 및 폴리글롯 제거); 아카이브는 폭탄 및 경로 탐색 확인; 선택적 오프라인 안티바이러스 (ClAMAV).
  • SVG 및 HTML 업로드는 삭제된 후 격리된 출처에서 제공되지 않는 한 거부됩니다.

7. 로깅, 감사 및 관리

  • 구조화된 로그: JSON, 수준 DEBUG/INFO/WARN/ERROR/CRITICAL, 모든 곳에 request_id, UTC 타임스탬프, 사용자 값에서 CR/LF 제거. 비밀번호, 토큰, 키, 세션 ID는 절대 로깅되지 않습니다.
  • 원격 syslog: 제한된 로컬 버퍼와 함께 TLS (RFC 5425)를 통한 RFC 5424; 호스트, 포트, TLS, CA는 Admin UI에서 구성 가능. rsyslog 컨테이너 없음.
  • 오류 알림: Admin UI에서 구성 가능한 SMTPS 및 웹훅, SSRF 검증됨, "Send test" 버튼, 조절됨.
  • PII 마스킹: Admin UI에서 전환 가능한 미들웨어.
  • 변조 방지 감사 추적: 추가 전용 테이블 (런타임 역할은 INSERT/SELECT만 있음), 각 행은 이전 행의 해시와 연결됨, syslog로 전달됨. 로그인, 실패, MFA 변경, 역할 변경, 구성 변경, 내보내기, API 키, 허니토큰 적중을 포함하며, 사용자, IP, 사용자 에이전트, UTC 시간 및 이전/이후 값을 기록합니다.
  • 관리자 대시보드: 사용 통계, 오류, 허니토큰 알림, 차단된 IP.
  • 예정된 정리: 비활성 계정 비활성화, 만료된 토큰/세션/멱등성 키 제거, 일일 암호화 백업 (키는 백업과 별도), 보존 정책 및 테스트된 복원 절차 (make restore-test).
  • 개인 데이터 (GDPR): 데이터 유형별 보존 기간, 사용자 데이터 내보내기 및 삭제, 제거 작업.

8. 인증, 신원 및 능동적 방어

  • 비밀번호: Argon2id (argon2-cffi 기본값 / RFC 9106, 최소 m=19 MiB, t=2, p=1), 매개변수가 변경되면 로그인 시 다시 해시. NIST SP 800-63B 정책: ≥ 12자, 최대 ≥ 64자, 구성 규칙 없음, 번들된 유출/일반 비밀번호 목록에 있는 경우 거부.
  • 로그인: 알 수 없는 사용자에 대해 동일한 응답 및 타이밍, 점진적 지연 + 계정별 및 IP별 조절 (DoS를 가능하게 하는 하드 잠금 방지).
  • 비밀번호 재설정: 해시되어 저장된 단일 사용 무작위 토큰, 30분 만료, 계정 존재 여부에 관계없이 동일한 응답, 재설정 후 모든 세션 취소.
  • 세션: 서버 측, 쿠키 __Host-session (HttpOnly; Secure; SameSite=Lax; Path=/), 로그인 및 권한 변경 시 ID 교체, 사용자는 활성 세션을 나열하고 취소할 수 있음. 브라우저 저장소에 JWT 없음. 서비스 간 JWT를 사용하는 경우: 알고리즘 고정, none 거부, aud/iss/exp 확인, 짧은 수명.
  • 관리자 세션: 1시간 유휴, 8시간 절대, 파괴적인 작업에 대한 재인증.
  • MFA: TOTP (해시된 복구 코드, 동일한 코드 재사용 거부) 및 WebAuthn/Passkeys. 관리자 계정에 MFA 필수.
  • 컨텍스트 감지: 알 수 없는 IP/기기에서의 관리자 로그인은 "New sign-in" 알림을 트리거하고 MFA 확인까지 파괴적인 권한을 제한합니다.
  • 부트스트랩 관리자: 첫 번째 부팅 시 무작위 비밀번호 생성, make admin-password를 통해 한 번 읽을 수 있으며, 첫 로그인 시 강제 재설정 + MFA 등록.
  • 긴급 계정 (선택 사항): SSO가 중단되었을 때 사용할 수 있는 로컬 관리자, 기본적으로 비활성화, 사용 시마다 중요한 경고 발생.
  • SSO: OIDC 코드 흐름 + PKCE, state 및 nonce 확인, ID 토큰 서명/aud/iss 확인; LDAPS 또는 인증서 확인이 포함된 StartTLS, LDAP 필터 값 이스케이프 (LDAP 인젝션). 디렉토리 그룹은 역할에 매핑됩니다.
  • SSO 구성, 두 가지 동등한 소스: 모든 OIDC 및 LDAP(S) 설정 (활성화 플래그, 발급자/서버 URL, 클라이언트 ID, 범위, 바인드 DN, 베이스 DN, 사용자/그룹 필터, CA 번들, 그룹-역할 매핑, 자동 프로비저닝)은 Admin UI 또는 환경 변수 (BACKEND_OIDC_*, BACKEND_LDAP_*)에서 설정할 수 있습니다.
    • 시크릿 (client_secret, 바인드 비밀번호)은 *_FILE 변수 또는 시크릿 제공자에서 가져오며, 프로덕션에서 일반 환경 변수 값은 절대 사용하지 않음; UI에서는 쓰기 전용 (••••last4)으로 표시됩니다.
    • 우선 순위: 환경 변수로 정의된 설정이 우선하며 Admin UI에서 "Managed by environment" 배지와 함께 읽기 전용으로 표시됩니다. 그 외의 모든 것은 편집 가능하며 데이터베이스에 암호화되어 저장됩니다.
    • 두 소스 모두 동일한 유효성 검사 (환경 로더와 Admin API가 공유하는 Pydantic 스키마); 유효하지 않은 환경 구성은 명확한 오류와 함께 시작을 실패하게 하고, 유효하지 않은 UI 입력은 저장 전에 거부됩니다.
    • Admin UI에는 "Test connection" 작업 (OIDC 디스커버리 + JWKS 가져오기, LDAP 바인드 + 샘플 그룹 검색)이 있으며 모든 변경 사항은 감사됩니다.

9. API 키 및 MCP

  • API 키: 접두사 (sk_), 해시로 저장 (SHA-256, bcrypt 또는 HMAC), 마지막 4자만 UI에 표시. 범위, 속도 제한, 만료 날짜가 있습니다. /api/v1/admin/api-keys 아래의 CRUD. 키는 전송 중에만 한 번 표시됩니다.
  • MCP 엔드포인트: mcp 도구 트리 아래에 위치 (backend/api/mcp/). 모든 MCP 도구는 MCP 프로토콜 및 표준 시큐어 코딩 규칙을 따릅니다. 특히 MCP 도구는 SSRF에 대해 검증되고, 속도가 제한되며, 모든 호출이 감사 로그에 기록되어야 합니다.

10. 모니터링 및 유지보수

  • 상태 엔드포인트: /-/health (Liveness), /-/ready (Readiness), /-/metrics (Prometheus). Admin UI에 기본 대시보드.
  • 유지보수 페이지: 배포 중 또는 긴 작업 중에 제공되는 기본 정적 페이지.

11. 사전 프로덕션 정리 절차

코드베이스를 프로덕션으로 전환하기 전에 다음 단계를 따르십시오:

  1. 모든 [todo], [fixme], [hack] 및 자리 표시자 텍스트를 제거합니다.
  2. 애플리케이션 시크릿이 하드코딩되지 않았는지 확인합니다 (git history도 확인).
  3. 모든 기본 사용자 및 자격 증명을 변경합니다.
  4. 디버그 엔드포인트 (예: /debug, /api/debug) 또는 uvicorn --reload를 비활성화합니다.
  5. 프론트엔드 빌드에서 소스 맵이 비활성화되었는지 확인합니다.
  6. 사용되지 않는 기능, 불필요한 패키지/라이브러리, 더미 데이터 및 테스트 코드를 제거합니다.
  7. 모든 설정이 안전하고 프로덕션 모드에 적합한지 확인합니다 (예: DEBUG = False).
  8. 실제 서비스 로드 하에서 보안 테스트 (make security-check)를 실행합니다.
  9. 모든 내부 서비스 (데이터베이스, 캐시 등)에 대한 기본 비밀번호가 변경되었는지 확인합니다.
  10. SSL/TLS 인증서가 유효하고 만료되지 않았는지 확인합니다.
  11. OS 및 모든 소프트웨어 구성 요소가 최신 보안 패치를 적용했는지 확인합니다.
  12. 민감한 정보 (비밀번호, API 키 등)를 인쇄하거나 로깅하는 코드를 제거합니다.
  13. 모든 API 엔드포인트가 적절한 인증, 권한 부여 및 유효성 검사를 적용하는지 확인합니다.
  14. 불필요한 포트와 서비스가 노출되지 않았는지 확인합니다.
  15. 로그가 민감한 정보를 캡처하지 않는지 확인합니다.
  16. 필요한 모든 규정 준수 요구 사항이 충족되었는지 확인합니다.
  17. 외부 접근 가능한 엔드포인트에 대한 속도 제한이 구성되었는지 확인합니다.
  18. 컨테이너가 루트리스로 구성되었고 필요한 최소 권한만 있는지 확인합니다.
  19. 백업 및 복원 절차가 테스트되었고 문서화되었는지 확인합니다.
  20. 재해 복구 및 비즈니스 연속성 계획이 마련되었는지 확인합니다.

12. 인증되지 않은 엔드포인트

다음 엔드포인트는 인증이 필요하지 않지만, 이 목록은 위협 모델에서 유지 관리해야 합니다.

  • /api/v1/auth/login
  • /api/v1/auth/register (활성화된 경우)
  • /api/v1/auth/reset-password
  • /api/v1/auth/forgot-password
  • /-/health
  • /-/ready
  • /-/maintenance (유지보수 중)

관련 스킬