安全應用程式腳手架 是做什麼的?
產生一個符合 ANSSI、CIS、FBI 和 OWASP ASVS Level 2 標準的「從設計上安全」的應用程式:TypeScript 前端、Python 後端、強化版 PostgreSQL。
佈局、README 和 UI 遵循 project-blueprint 技能。此技能中的安全規則優先於任何便利性或 UX 規則。
參考檔案(產生對應成品時請讀取)
- reference/docker-compose.yml: 強化版 Compose 檔案,包含密碼引導程序。
- reference/nginx.conf: 反向代理,支援 TLS 1.3、混合後量子密碼學、安全標頭、速率限制。
- reference/security-tests.md: 強制性的安全測試矩陣。
使用時機
- 啟動、搭建或架構一個新的 Web 應用程式或服務。
- 需求中提及 ANSSI、CIS、FBI、OWASP、強化、無 root 權限、合規。
- 添加驗證、授權、檔案上傳、稽核日誌、管理員功能、部署檔案或 MCP 端點。
部署目標: 僅限 Docker 和 rootless Podman。除非使用者明確要求,否則不要產生 Kubernetes、Helm 或其他編排器清單。
0. 威脅模型
- 建立
docs/security/threat-model.md(≤ 1 頁):資產、信任邊界、參與者、主要風險 (STRIDE) 以及對應的控制措施。當出現新的信任邊界(如上傳、Webhook、LLM、MCP)時,更新此文件。
1. 容器與執行時期
- 無 root 權限: 每個映像檔都以數字
USER(例如USER 10001:10001)結尾,包括 Web 伺服器(nginxinc/nginx-unprivileged,連接埠 > 1024)。 - 最小化、釘選映像檔: 多階段建置;執行階段為 distroless 或 slim,無 shell、編譯器或套件管理器;排除開發依賴。基礎映像檔由摘要釘選。使用最新的穩定版 Python。
- 強化設定:
read_only、tmpfs用於可寫入路徑、cap_drop: [ALL]、no-new-privileges、執行階段預設 seccomp 設定檔(絕不使用unconfined)、pids_limit、記憶體限制、健康檢查、停用核心傾印(ulimits: core: 0)。僅反向代理發佈連接埠;資料庫網路為internal: true。絕不掛載 Docker/Podman 的 socket。 - 無子程序: 不使用
subprocess、os.system、shell=True。透過以下方式強制執行:映像檔中無 shell、SAST 規則、以及在每個 Worker 啟動後載入的處理序內 seccomp 過濾器(拒絕execve/execveat)(容器層級的拒絕會阻止進入點本身啟動)。 - 首次執行保證: 在乾淨的程式碼簽出後,
docker compose up(也支援docker-compose up和podman compose up)能一試成功:無需.env、無需手動步驟、無需容器引擎以外的先決條件。映像檔自動建置(build:),僅使用 Docker Compose v2 和 podman-compose 支援的 Compose Specification 功能,不使用儲存庫外的主機路徑,發佈的連接埠 > 1024,不設定 CPU 限制(在許多 rootless cgroup 設定中不可用)。make up是相同指令的精簡包裝。 - 無硬編碼密碼: 一個一次性
init服務會將密碼產生至一個命名磁碟區(0600),並透過*_FILE變數使用。在正式環境中,密碼從檔案讀取,而非環境變數。 - 隔離執行: 所有 JS/CSS/字型/圖示均打包;無 CDN、執行時期下載或遙測。在離線建置時,依賴項來自內部鏡像(Nexus、Artifactory、devpi、Verdaccio)。
- Vault 就緒: 單一密碼提供者抽象層(預設為
file,正式環境使用vault/sops)。 - 內部 TLS: 後端 ↔ 資料庫之間使用 TLS;服務之間可選用 mTLS。
2. 供應鏈與掃描
- 鎖定依賴: 提交 lockfile;
npm ci、uv sync --frozen或pip install --require-hashes。若無套件需要安裝腳本(需加入允許清單),則.npmrc設定ignore-scripts=true。 - 建置前閘道:
npm audit --audit-level=high和pip-audit在退出碼 > 0 時使建置失敗。 - SAST 與密碼掃描: pre-commit 勾點包含
ruff、bandit/semgrep、eslint(+eslint-plugin-security)、gitleaks。 - 映像檔掃描(
make scan):trivy image(CVE + 密碼 + 錯誤設定)、trivy config(針對 Dockerfile 和 Compose)、oscap-podman(或oscap-docker)針對基礎作業系統的 CIS 設定檔。 - 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,無執行時期 CSS-in-JS 注入不含 nonce 的<style>。偏好使用編譯後的 CSS。啟用 Trusted Types(require-trusted-types-for 'script')。 - 零信任輸入: 每個表單使用 typed Zod schema,並與 API 型別共用。絕不在不受信任的資料上使用
dangerouslySetInnerHTML/v-html;若無法避免使用 RTF 內容,則使用 DOMPurify。 - 等冪性: API 客戶端為每個 POST/PUT/PATCH/DELETE 請求附加一個
Idempotency-Key(UUIDv4),每次使用者動作產生一次,並在重試時重複使用。 - CSRF: 自訂標頭(
X-Requested-With)+ CSRF Token;後端也會檢查Origin/Sec-Fetch-Site。僅使用 CORS 允許清單,絕不搭配憑證使用*。 - 開放式重新導向: 登入後的
next/returnUrl僅接受以單一/開頭的相對路徑。 - 套件中無密碼: 正式環境中無 source map;
localStorage/sessionStorage中不存放敏感資料。
4. 後端 (Python) 與資料庫
- 驗證: 每個請求主體、查詢參數、路徑參數和標頭均透過 Pydantic 驗證,包含最大長度及
extra="forbid"(防止大量賦值:role、owner_id、is_admin無法從輸入綁定)。 - 資源限制: 最大請求主體大小、最大 JSON 深度/陣列長度、最大頁面大小(例如 100)、伺服器端逾時。使用者輸入上的正則表達式有界限或使用線性時間引擎 (
re2) 以避免 ReDoS。 - 安全解析: 不使用
pickle、marshal、yaml.load(使用yaml.safe_load)、eval。XML 使用defusedxml。範本來源中無使用者輸入(SSTI)。檔案路徑需解析並對照基礎目錄進行檢查(防止路徑遍歷)。 - 等冪性儲存:
(user_id, key) -> request_hash, status, response,TTL 為 24 小時。相同金鑰與相同雜湊值會回傳已儲存回應;不同雜湊值則回傳422。這可防止重複請求;重放攻擊的防護來自 TLS、CSRF Token 和短會話期限。 - SQL: 僅使用 ORM 或參數化查詢;動態識別符(
ORDER BY、欄位名稱)需透過允許清單。 - 資料欄位層級加密: PII 在應用程式中使用 AES-256-GCM 加密,採用信封加密(每筆記錄的 DEK 由密碼提供者的主金鑰包裝),使用
key_version欄位進行輪換,可搜尋欄位使用 HMAC-SHA256 盲索引。主金鑰絕不儲存在資料庫或資料庫備份中。 - 資料庫強化: 最小化 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(Webhook、syslog、LLM、OIDC)均經過驗證:僅允許
https(除非有明確允許清單),若解析後的 IP 為 loopback/link-local/metadata(169.254.0.0/16、fd00:ec2::254)或私有 IP(除非允許清單中有),則拒絕,DNS 解析後重新檢查(防止 DNS 綁架),無跨主機重新導向,嚴格的逾時設定。 - 對外 Webhook: 使用 HMAC-SHA256 簽署(
X-Signature+ 時間戳記),以便接收方驗證。 - 電子郵件: 標頭值中去除 CR/LF;使用帶有憑證驗證的 SMTPS。
- 匯出: 以
=、+、-、@、Tab 或 CR 開頭的 CSV/XLSX 儲存格前綴加上'(防止公式注入)。 - 速率限制: 針對登入、密碼重設、MFA 驗證、API 金鑰、匯出、上傳和昂貴的端點。
- 回應: 已驗證的 API 回應設定
Cache-Control: no-store。使用包含request_id的通用錯誤訊息;堆疊追蹤僅記錄在日誌中。在正式環境中,OpenAPI UI 應停用或僅限管理員使用。
5. 授權
- 預設拒絕: 每個路由宣告其所需的權限;未宣告的路由會在啟動或測試時失敗。
- RBAC:角色對應至權限(而非直接在程式碼中檢查角色)。
- 物件層級檢查 (IDOR/BOLA): 在儲存庫層級對每個依 ID 進行的讀取/寫入進行所有權或租戶檢查。對現有物件的未授權存取回傳
404。 - 功能層級檢查: 管理員路由位於
/api/v1/admin/*下,由單一依賴項保護,絕不單純隱藏 UI。 - 敏感操作(角色變更、金鑰建立、匯出、刪除使用者)需要近期重新驗證;可選用雙人核准流程來將角色提升至管理員。
6. 檔案上傳(若有的話)
- 在代理和應用程式層級設定大小限制;允許的副檔名清單 和 Magic Byte 檢查。
- 儲存在 Web 根目錄之外(或物件儲存),使用隨機檔案名稱,以
Content-Disposition: attachment和X-Content-Type-Options: nosniff提供服務。 - 圖片重新編碼(去除 EXIF 和多重語言檔案);壓縮檔檢查是否有壓縮炸彈和路徑遍歷;可選用離線防毒軟體(ClamAV)。
- 拒絕 SVG 和 HTML 上傳,除非經過清理並從分離的來源提供服務。
7. 日誌、稽核與管理
- 結構化日誌: JSON 格式,層級為 DEBUG/INFO/WARN/ERROR/CRITICAL,所有地方都包含
request_id,UTC 時間戳記,使用者值中去掉 CR/LF。從不記錄密碼、Token、金鑰、會話 ID。 - 遠端 syslog: 透過 TLS 的 RFC 5424(RFC 5425),帶有有界本地緩衝區;主機、連接埠、TLS、CA 可從管理員 UI 設定。無需 rsyslog 容器。
- 錯誤通知: 可從管理員 UI 設定 SMTPS 和 Webhook,經過 SSRF 驗證,包含「傳送測試」按鈕,並有速率限制。
- PII 遮罩: 可從管理員 UI 切換的中介軟體。
- 防篡改稽核軌跡: 僅附加的資料表(執行時期角色僅具備
INSERT/SELECT權限),每一列與前一列的雜湊值鏈接,並轉發至 syslog。涵蓋:登入、失敗、MFA 變更、角色變更、設定變更、匯出、API 金鑰、蜜令命中;記錄使用者、IP、使用者代理、UTC 時間以及變更前/後的值。 - 管理員儀表板: 使用統計、錯誤、蜜令警報、被封鎖的 IP。
- 定期清理: 停用非活躍帳戶、清除過期的 Token/會話/等冪性金鑰、每日加密備份(金鑰與備份分開儲存)、保留政策以及經過測試的還原程序(
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)。
- 密碼重設: 一次性隨機 Token,儲存時已雜湊,30 分鐘有效期,無論帳戶是否存在,回應相同,重設後撤銷所有會話。
- 會話: 伺服器端,Cookie 名稱為
__Host-session(HttpOnly; Secure; SameSite=Lax; Path=/),ID 在登入和權限變更時輪換,使用者可以列出和撤銷其活躍會話。瀏覽器儲存中不使用 JWT;若 JWT 用於服務間通訊:演算法固定、拒絕none、檢查aud/iss/exp、短生命週期。 - 管理員會話: 閒置 1 小時,絕對時間 8 小時,破壞性操作需要重新驗證。
- MFA: TOTP(已雜湊的恢復碼,拒絕重放相同代碼)和 WebAuthn/Passkeys。管理員帳戶強制啟用 MFA。
- 情境偵測: 來自未知 IP/裝置的管理員登入會觸發「新的登入」通知,並限制破壞性權限,直到透過 MFA 確認。
- 引導管理員: 首次啟動時產生隨機密碼,可透過
make admin-password讀取一次,首次登入時強制重設密碼並註冊 MFA。 - 緊急帳戶(可選): 當 SSO 中斷時可使用的本機管理員,預設停用,每次使用都會觸發嚴重警報。
- SSO: OIDC 授權碼流程 + PKCE,驗證
state和nonce,檢查 ID Token 的簽章/aud/iss;LDAPS 或 StartTLS 搭配憑證驗證,LDAP 過濾器值經過跳脫(防止 LDAP 注入)。目錄群組對應至角色。 - SSO 設定,兩個等效來源: 每個 OIDC 和 LDAP(S) 設定(啟用旗標、Issuer/伺服器 URL、Client ID、Scope、Bind DN、Base DN、使用者/群組過濾器、CA 套件、群組到角色對應、自動佈建)可以從管理員 UI 或從環境變數(
BACKEND_OIDC_*、BACKEND_LDAP_*)設定。- 密碼 (
client_secret、Bind Password) 來自*_FILE變數或密碼提供者,絕不來自正式環境中的純文字環境變數;在 UI 中它們是唯寫的(••••後4碼)。 - 優先順序:由環境變數定義的設定優先,並在管理員 UI 中以唯讀方式顯示,附帶「由環境管理」徽章;其他所有設定皆可編輯並以加密形式儲存在資料庫中。
- 兩個來源使用相同的驗證邏輯(由環境變數載入器和管理員 API 共用的 Pydantic Schema);無效的環境變數設定會導致啟動失敗並顯示清晰的錯誤訊息,無效的 UI 輸入會在儲存前被拒絕。
- 管理員 UI 具有「測試連線」功能(OIDC 發現 + JWKS 獲取,LDAP Bind + 樣本群組搜尋),且每次變更都會被稽核。
- 每個來源的設定變更都會被記錄在稽核軌跡中,並觸發即時通知。
- 自動佈建的使用者會獲得一個預設角色(可設定),並在每次登入時同步其群組成員資格。
- 密碼 (
9. 部署
- Docker Compose / Podman Compose: 如前所述,所有服務已定義並強化。
- 生產環境建置: 可透過
make build-production命令產生一個僅包含必要服務的最小化 Docker Compose 檔案(僅app、db、cache),並使用docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d啟動。 - 映像檔簽章驗證: 生產環境部署腳本應在啟動任何容器之前,驗證所有使用映像檔的 Cosign 簽章。
- 資料庫備份: 每日加密備份,使用
pg_dump並透過 GPG 加密,儲存在獨立於應用程式伺服器的位置。 - 上線前檢查清單: 產生
docs/operations/go-live-checklist.md,包含以下項目:- 所有環境變數已設定且安全
- 密碼已從預設值變更
- TLS 憑證已安裝且有效
- 防火牆規則已套用
- 入侵偵測系統 (IDS) 已啟用
- 備份已設定並測試
- 監控和警報已設定
- 事件應變計畫已記錄
- 安全聯絡人已指定
10. MCP 端點
- 若使用者要求 MCP 端點,則產生一個遵循 MCP 規範的伺服器端點,位於
/api/v1/mcp/*。 - MCP 端點應使用與其他 API 相同的驗證和授權機制。
- 應為 MCP 端點啟用速率限制和審計日誌記錄。
11. 清理程序
- 上線前清理: 產生一個
make pre-launch-cleanup命令,執行以下操作:- 移除所有開發用的 .env 檔案(如果存在)
- 移除開發用的啟動腳本(
make dev等) - 確保所有環境變數都已從生產環境設定檔中正確設定
- 驗證所有密碼都已從預設值變更
- 執行完整的掃描套件 (
make scan) - 執行 DAST 掃描(如果已配置)
- 產生最終的 SBOM (
make sbom) - 驗證所有映像檔都已簽署
- 標記發行版本
- 此程序應在部署至生產環境前執行。
12. 文件
- 產生
docs/security/README.md,總結所有安全措施和設定。 - 產生
docs/operations/README.md,包含日常操作程序。 - 產生
docs/development/README.md,包含開發設定指南。 - 所有文件應使用英文撰寫。
13. 測試
- 產生涵蓋以下項目的測試:
- 所有 API 端點的單元測試
- 關鍵流程的整合測試(登入、註冊、密碼重設)
- 授權規則的測試(角色權限、物件層級檢查)
- 檔案上傳的安全性測試
- 速率限制測試
- SQL 注入和 XSS 的滲透測試
- 測試應使用
pytest(Python)和vitest(TypeScript)執行。
14. 常見問題與疑難排解
- 若
docker compose up失敗,請檢查 Docker 版本是否為 v2 或更高版本。 - 若連接埠已被佔用,請修改
docker-compose.yml中的連接埠對應。 - 若認證失敗,請執行
make admin-password來取得管理員密碼。 - 若遇到 SSL 錯誤,請確保 CA 憑證已正確設定。