cover

安全掃描:你的映像檔和依賴套件藏了什麼漏洞?

2020 年 SolarWinds 供應鏈攻擊影響了上萬個組織,2021 年 Log4Shell(CVE-2021-44228)讓全球 Java 應用暴露在遠端程式碼執行風險之下,2024 年 xz-utils 後門事件差點讓整個 Linux 生態系統淪陷。這些事件的共同點:問題不在你自己寫的程式碼,而在你「引用」的東西——Base Image 裡的系統套件、npm/pip 裡的第三方依賴、甚至是建置工具本身。當你的 Dockerfile 寫 FROM node:20 時,你繼承了那個 image 裡所有已知和未知的漏洞。當你 npm install 時,你把整棵依賴樹的風險都拉進了專案。

安全掃描的目標很簡單:在漏洞被攻擊者利用之前,先找到它。不是部署到 production 之後才去掃,而是在 CI/CD pipeline 的每個階段都掃——程式碼寫完掃一次(SAST),映像檔 build 完掃一次(Image Scan),跑起來之後再掃一次(DAST)。這就是「Shift-left Security」的核心思想:安全檢查越早做,修復成本越低。這篇文章會完整走過 Container Image 掃描、Dependency 掃描、SAST/DAST 的概念和實作,重點放在 Trivy(目前最流行的開源掃描工具)以及如何把掃描整合進 CD pipeline 裡。

架構概覽

flowchart LR
    Code["原始碼\nSource Code"] --> SAST["SAST\n靜態分析"]
    SAST --> DepScan["Dependency Scan\n依賴套件掃描"]
    DepScan --> Build["Docker Build\n映像檔建置"]
    Build --> ImageScan["Image Scan\nTrivy / Snyk"]
    ImageScan --> DAST["DAST\n動態掃描"]
    DAST --> Report["安全報告\nVulnerability Report"]
    Report -->|PASS| Deploy["部署 Production"]
    Report -->|FAIL| Block["阻擋部署\n通知開發者"]

架構概覽

flowchart LR
  subgraph Dev["開發階段"]
    Code[程式碼撰寫] -->|git push| Repo[Git Repository]
  end

  subgraph CI["CI Pipeline"]
    direction TB
    SAST[SAST\n靜態原始碼掃描] -->|pass| DepScan[Dependency Scan\nnpm audit / pip-audit]
    DepScan -->|pass| Build[Docker Build]
    Build -->|image| ImgScan[Image Scan\nTrivy / Clair]
    ImgScan -->|pass| Push[Push to Registry]
  end

  subgraph Registry["映像庫"]
    Harbor[Harbor\n自動掃描]
  end

  subgraph Deploy["部署階段"]
    Staging[Staging 環境]
    DAST[DAST\n動態應用掃描]
    Prod[Production]
  end

  Repo --> CI
  Push --> Harbor
  Harbor -->|pull| Staging
  Staging --> DAST
  DAST -->|pass| Prod

  style SAST fill:#4a90d9,color:#fff
  style DepScan fill:#4a90d9,color:#fff
  style ImgScan fill:#e74c3c,color:#fff
  style DAST fill:#f39c12,color:#fff

整個安全掃描策略覆蓋四個階段:SAST 在程式碼階段抓出潛在的安全缺陷(SQL Injection、硬編碼密碼、不安全的函式呼叫);Dependency Scan 檢查第三方套件是否有已知 CVE;Image Scan 在映像檔建置後掃描 OS 層和應用層的漏洞;DAST 在 staging 環境對運行中的應用做黑箱測試。每一層都是一道閘門,通過才能進入下一階段。

核心概念

  1. Container Image Scanning(容器映像檔掃描):映像檔掃描會解析 image 的每一層 layer,識別出安裝了哪些 OS 套件(apt/apk/yum)和應用依賴(npm/pip/maven),然後比對 CVE 資料庫(NVD、Alpine SecDB、Debian Security Tracker 等)找出已知漏洞。常見工具:Trivy(Aqua Security 開源,掃描速度快、支援格式多)、Clair(CoreOS 開發,需要搭配 PostgreSQL)、Harbor 內建掃描器(其實就是 Trivy adapter)。掃描結果會列出每個漏洞的 CVE ID、嚴重程度(Critical/High/Medium/Low)、受影響的套件版本、以及修復版本。重點不是「零漏洞」(幾乎不可能),而是「沒有 Critical 和 High 等級的可修復漏洞」。

  2. Dependency Scanning(依賴套件掃描):和 Image Scanning 不同,Dependency Scanning 專注在應用層的第三方套件。它讀取 package-lock.jsonrequirements.txtpom.xmlgo.sum 等 lock file,比對已知漏洞資料庫。每個語言生態系都有自己的工具:Node.js 用 npm audit、Python 用 pip-audit、Java 用 OWASP Dependency-Check、Go 用 govulncheck。這類掃描應該在 CI 的最早期執行——甚至在 build 之前——因為如果依賴有嚴重漏洞,整個 build 就不應該繼續。

  3. SAST(Static Application Security Testing,靜態應用安全測試):SAST 分析原始碼本身,不需要編譯或執行。它能抓出的問題包括:SQL Injection(字串拼接 SQL 查詢)、XSS(未經轉義的使用者輸入直接輸出到 HTML)、硬編碼的密碼或 API Key、不安全的加密演算法(MD5/SHA1)、路徑遍歷(Path Traversal)等。常見工具:Semgrep(開源規則引擎,支援多語言)、SonarQube(程式碼品質 + 安全)、GitLab SAST(內建在 GitLab Ultimate 裡,底層用了多個開源引擎)。SAST 的缺點是誤報率高——很多它標記的問題在特定上下文中其實不是漏洞。

  4. DAST(Dynamic Application Security Testing,動態應用安全測試):DAST 是對運行中的應用做黑箱測試,模擬攻擊者從外部發送惡意請求,看應用會不會中招。它能發現的問題:CSRF 漏洞、HTTP header 設定不當(缺少 Content-Security-Policy、X-Frame-Options)、Session 管理缺陷、Server-side Request Forgery(SSRF)。常見工具:OWASP ZAP(開源,最流行的 DAST 工具)、Burp Suite(商業版功能強大)、GitLab DAST(整合在 pipeline 裡自動執行)。DAST 的前提是要有可以存取的環境,所以通常在部署到 staging 之後才執行。

  5. SCA(Software Composition Analysis,軟體組成分析):SCA 除了找漏洞之外,還處理授權合規問題。你用了一個 GPL-3.0 的套件,但你的專案是閉源商業軟體——這可能有法律風險。SCA 工具會列出專案裡所有第三方依賴的授權條款(MIT、Apache-2.0、GPL、BSD 等),標記出有合規風險的依賴。Snyk、FOSSA、WhiteSource(現在叫 Mend)都是 SCA 工具。在大公司,法務部門通常會要求 SCA 報告才允許上線。

  6. Shift-left Security(安全左移):傳統做法是在部署前才做安全審查——開發花了兩個月寫完功能,然後安全團隊花兩週做 penetration test,發現一堆問題,打回去改,又花兩週。Shift-left 的核心理念是把安全檢查搬到開發流程的最早期:IDE 裡裝 linter 即時抓漏洞、pre-commit hook 擋住含有 secret 的提交、CI pipeline 每次 push 都做 SAST + Dependency Scan。問題發現得越早,修復成本越低——在 IDE 裡改只要幾秒,在 production 裡修可能要半天做 hotfix + rollback。

工具比較

特性TrivySnykClairGitLab Built-in
授權開源 (Apache-2.0)免費方案 + 商業版開源 (Apache-2.0)GitLab Ultimate
Image Scanning是(底層用 Trivy)
Dependency Scanning是(filesystem mode)是(核心功能)
SAST有限(misconfiguration)是(Snyk Code)是(多引擎整合)
IaC Scanning是(Dockerfile, K8s, Terraform)
掃描速度快(本地 DB)中等(API 呼叫)慢(需 PostgreSQL)中等
CI 整合難度低(單一 binary)低(CLI + API)高(需額外部署)內建(零設定)
修復建議列出修復版本自動 PR 修復列出修復版本列出修復版本
離線使用支援(下載 DB)不支援支援不支援
適合場景中小團隊、CI 整合需要自動修復 PR搭配 Harbor/Quay已用 GitLab Ultimate

Trivy 是目前最推薦的選擇——它是單一 binary,不需要額外部署資料庫或伺服器,掃描速度快,支援的格式最多(container image、filesystem、git repo、IaC config),而且完全開源。Snyk 的優勢在於它能自動開 PR 幫你升級有漏洞的依賴版本,對不想手動追蹤每個 CVE 的團隊很方便,但免費方案有掃描次數限制。

實作範例

範例一:Trivy CLI 掃描(Image、Filesystem、Config)

Trivy 最大的優勢是一個工具搞定所有掃描場景。以下是三種最常用的掃描方式。

# ===== 1. 掃描 Container Image =====
# 掃描本地 Docker image,列出所有已知漏洞
trivy image myapp:latest
 
# 只顯示 CRITICAL 和 HIGH 等級,忽略沒有修復版本的漏洞
trivy image --severity CRITICAL,HIGH --ignore-unfixed myapp:latest
 
# 掃描遠端 Registry 上的 image(不需要 docker pull)
trivy image --username $HARBOR_USER --password $HARBOR_TOKEN \
  harbor.example.com/ec/api:v1.2.3
 
# 輸出 JSON 格式(方便後續自動化處理)
trivy image --format json --output trivy-report.json myapp:latest
 
# 設定 exit code:有 CRITICAL/HIGH 時回傳非零,讓 CI 失敗
trivy image --exit-code 1 --severity CRITICAL,HIGH myapp:latest
 
# ===== 2. 掃描 Filesystem(應用依賴) =====
# 掃描專案目錄,自動偵測 package-lock.json、requirements.txt 等
trivy filesystem --severity CRITICAL,HIGH .
 
# 只掃描特定語言的依賴
trivy filesystem --scanners vuln --skip-dirs node_modules .
 
# ===== 3. 掃描 Config(IaC 設定檔) =====
# 掃描 Dockerfile、docker-compose.yml、Kubernetes YAML 的不安全設定
trivy config .
 
# 掃描 Dockerfile 是否使用了 root user、是否有不安全的指令
trivy config --policy-bundle-repository ghcr.io/aquasecurity/trivy-policies \
  Dockerfile
 
# ===== 4. 更新漏洞資料庫 =====
# 離線環境需要手動下載 DB
trivy image --download-db-only
# DB 存放在 ~/.cache/trivy/db/

範例二:GitLab CI 整合 Trivy(Pipeline 掃描 + 阻擋部署)

把 Trivy 整合到 CD pipeline 裡,在 build 完映像檔後自動掃描,CRITICAL 或 HIGH 漏洞直接讓 pipeline 失敗。

# .gitlab-ci.yml - 安全掃描整合
variables:
  REGISTRY: "harbor.example.com"
  IMAGE: "${REGISTRY}/ec/${CI_PROJECT_NAME}"
  TRIVY_SEVERITY: "CRITICAL,HIGH"
 
stages:
  - lint
  - dependency-scan
  - build
  - image-scan
  - deploy
 
# ===== SAST(靜態分析)=====
sast:semgrep:
  stage: lint
  image: returntocorp/semgrep:latest
  script:
    - semgrep scan --config auto --error --json --output semgrep-report.json .
  artifacts:
    reports:
      sast: semgrep-report.json
    expire_in: 7 days
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == "main"
  allow_failure: true  # SAST 誤報率高,初期建議不擋 pipeline
 
# ===== Dependency Scanning =====
dependency-scan:
  stage: dependency-scan
  image:
    name: aquasec/trivy:latest
    entrypoint: [""]
  script:
    - trivy filesystem
      --exit-code 1
      --severity ${TRIVY_SEVERITY}
      --ignore-unfixed
      --format table
      .
    # 同時輸出 JSON 報告
    - trivy filesystem
      --format json
      --output dependency-report.json
      .
  artifacts:
    paths:
      - dependency-report.json
    expire_in: 7 days
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH == "main"
 
# ===== Build =====
build:docker:
  stage: build
  image: docker:24
  services:
    - docker:24-dind
  before_script:
    - docker login -u $HARBOR_ROBOT_USER -p $HARBOR_ROBOT_TOKEN $REGISTRY
  script:
    - docker build -t ${IMAGE}:${CI_COMMIT_SHA} .
    - docker push ${IMAGE}:${CI_COMMIT_SHA}
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
 
# ===== Image Scanning =====
image-scan:trivy:
  stage: image-scan
  image:
    name: aquasec/trivy:latest
    entrypoint: [""]
  variables:
    TRIVY_USERNAME: $HARBOR_ROBOT_USER
    TRIVY_PASSWORD: $HARBOR_ROBOT_TOKEN
  script:
    # 嚴格模式:有 CRITICAL/HIGH 就讓 pipeline 失敗
    - trivy image
      --exit-code 1
      --severity ${TRIVY_SEVERITY}
      --ignore-unfixed
      --format table
      ${IMAGE}:${CI_COMMIT_SHA}
    # 完整報告(包含所有等級)
    - trivy image
      --format json
      --output trivy-image-report.json
      ${IMAGE}:${CI_COMMIT_SHA}
  artifacts:
    paths:
      - trivy-image-report.json
    reports:
      container_scanning: trivy-image-report.json
    expire_in: 7 days
  rules:
    - if: $CI_COMMIT_BRANCH == "main"
 
# ===== Deploy(只有掃描通過才能部署)=====
deploy:dev:
  stage: deploy
  needs:
    - build:docker
    - image-scan:trivy
  image: alpine:latest
  environment:
    name: dev
  script:
    - echo "Deploying scanned and verified image..."
    # 部署邏輯省略
  rules:
    - if: $CI_COMMIT_BRANCH == "main"

這個 pipeline 的關鍵設計:dependency-scan 在 build 之前執行,如果依賴有嚴重漏洞就不浪費時間 build image。image-scan 在 build 之後、deploy 之前執行,掃描 image 的 OS 層漏洞。deploy:dev 使用 needs 確保必須通過 image scan 才能部署。初期建議 SAST 用 allow_failure: true,等團隊熟悉掃描結果後再改成阻擋模式。

範例三:npm audit / pip-audit 依賴掃描

不需要 Trivy 也能做基本的依賴掃描,每個語言生態系都有原生的安全檢查工具。

# ===== Node.js:npm audit =====
# 檢查 package-lock.json 裡的已知漏洞
npm audit
 
# 只顯示 high 和 critical 等級
npm audit --audit-level=high
 
# 輸出 JSON 格式(方便 CI 解析)
npm audit --json > npm-audit-report.json
 
# 自動修復可以安全升級的依賴(minor/patch 版本)
npm audit fix
 
# 強制修復(包含 breaking changes 的 major 版本升級,慎用)
npm audit fix --force
 
# 在 CI 裡使用:有 high/critical 漏洞時讓 pipeline 失敗
npm audit --audit-level=high || exit 1
 
# ===== Python:pip-audit =====
# 安裝 pip-audit
pip install pip-audit
 
# 掃描當前環境安裝的所有套件
pip-audit
 
# 掃描 requirements.txt(不需要真的安裝套件)
pip-audit -r requirements.txt
 
# 只顯示有修復版本的漏洞
pip-audit --fix --dry-run
 
# 輸出 JSON 格式
pip-audit -f json -o pip-audit-report.json
 
# 在 CI 裡使用:有漏洞時回傳非零 exit code(預設行為)
pip-audit -r requirements.txt
 
# ===== Go:govulncheck =====
# 安裝 govulncheck
go install golang.org/x/vuln/cmd/govulncheck@latest
 
# 掃描當前 module
govulncheck ./...
 
# ===== Java:OWASP Dependency-Check =====
# Maven plugin
mvn org.owasp:dependency-check-maven:check
 
# Gradle plugin(需在 build.gradle 裡加 plugin)
gradle dependencyCheckAnalyze

範例四:安全的 Dockerfile 最佳實踐

映像檔掃描能找到漏洞,但更好的策略是從源頭減少攻擊面——寫出更安全的 Dockerfile。

# ===== 不好的寫法 =====
# FROM node:20           # 完整 image,1GB+,包含大量不需要的工具
# RUN npm install        # 安裝 dev dependencies 進 production image
# COPY . .               # 複製 .env、.git 等敏感檔案
# CMD ["node", "app.js"] # 以 root 身份運行
 
# ===== 推薦寫法:多階段建置 + 最小化攻擊面 =====
 
# Stage 1: Build(安裝依賴、編譯)
FROM node:20-alpine AS builder
WORKDIR /app
 
# 先複製 lock file,利用 Docker layer cache
COPY package.json package-lock.json ./
RUN npm ci --ignore-scripts
 
# 複製原始碼並編譯
COPY src/ ./src/
COPY tsconfig.json ./
RUN npm run build
 
# 移除 devDependencies,只保留 production 依賴
RUN npm ci --omit=dev --ignore-scripts
 
# Stage 2: Production(只複製必要的檔案)
FROM node:20-alpine AS production
 
# 安全加固:安裝安全更新
RUN apk update && apk upgrade --no-cache \
    && rm -rf /var/cache/apk/*
 
# 建立非 root 使用者
RUN addgroup -g 1001 -S appgroup \
    && adduser -u 1001 -S appuser -G appgroup
 
WORKDIR /app
 
# 只從 builder 階段複製 production 需要的東西
COPY --from=builder --chown=appuser:appgroup /app/dist ./dist
COPY --from=builder --chown=appuser:appgroup /app/node_modules ./node_modules
COPY --from=builder --chown=appuser:appgroup /app/package.json ./
 
# 移除不需要的工具(減少攻擊面)
# Alpine 預設已經很精簡,但可以進一步移除 shell(極端情況)
# RUN rm -rf /bin/sh /bin/ash
 
# 不要在 image 裡存放 secret
# ENV DATABASE_URL="..." ← 絕對不要這樣做
 
# 使用非 root 使用者執行
USER appuser
 
# 設定唯讀檔案系統(搭配 docker run --read-only)
# 暴露必要的 port
EXPOSE 3000
 
# 健康檢查
HEALTHCHECK --interval=30s --timeout=5s --retries=3 \
  CMD wget -qO- http://localhost:3000/health || exit 1
 
CMD ["node", "dist/app.js"]

多階段建置的核心效果:production image 裡沒有 TypeScript 原始碼、沒有 devDependencies、沒有 build 工具,只有編譯後的 JavaScript 和 production 依賴。image 大小從可能的 1GB+ 降到 150-200MB,可被攻擊的套件數量也大幅減少。加上非 root 使用者執行,即使應用被入侵,攻擊者的權限也被限制在低權限的容器環境裡。

範例五:Harbor 自動掃描設定

Harbor 整合了 Trivy 掃描器,可以在映像檔被 push 時自動觸發掃描,甚至阻止有嚴重漏洞的映像檔被 pull。

# ===== Harbor 安裝時啟用 Trivy =====
# 在 Harbor 安裝目錄下
./install.sh --with-trivy
 
# ===== 透過 Harbor API 設定自動掃描策略 =====
 
# 1. 對 Project 啟用「Push 時自動掃描」
curl -X PUT "https://harbor.example.com/api/v2.0/projects/ec" \
  -H "Content-Type: application/json" \
  -u "admin:${HARBOR_ADMIN_PASSWORD}" \
  -d '{
    "metadata": {
      "auto_scan": "true"
    }
  }'
 
# 2. 設定漏洞阻擋策略:阻止 pull 含有 Critical 漏洞的映像檔
curl -X PUT "https://harbor.example.com/api/v2.0/projects/ec" \
  -H "Content-Type: application/json" \
  -u "admin:${HARBOR_ADMIN_PASSWORD}" \
  -d '{
    "metadata": {
      "auto_scan": "true",
      "prevent_vul": "true",
      "severity": "critical"
    }
  }'
# severity 可設定為:critical, high, medium, low
# 設為 "high" 代表 Critical 和 High 等級的漏洞都會被阻擋
 
# 3. 手動觸發全 Project 掃描(更新 CVE 資料庫後使用)
curl -X POST "https://harbor.example.com/api/v2.0/projects/ec/repositories/api/artifacts/latest/scan" \
  -H "Content-Type: application/json" \
  -u "admin:${HARBOR_ADMIN_PASSWORD}"
 
# 4. 查詢掃描結果
curl -s "https://harbor.example.com/api/v2.0/projects/ec/repositories/api/artifacts/latest?with_scan_overview=true" \
  -u "admin:${HARBOR_ADMIN_PASSWORD}" | jq '.scan_overview'
 
# 5. 定期掃描排程(Harbor 2.x 支援)
# 在 Harbor Web UI → Administration → Interrogation Services
# 設定 Vulnerability Scanning 的 Schedule:
# - 每天 02:00 自動掃描所有映像檔
# - 這能確保新發布的 CVE 被及時偵測到

Harbor 的自動掃描機制和 CI pipeline 掃描是互補的:CI pipeline 掃描確保 build 當下沒有已知漏洞;Harbor 的定期掃描確保之前 build 時還不存在的新 CVE 也能被偵測到。設定 prevent_vul 後,即使映像檔已經存在於 Registry 裡,只要新的掃描發現了嚴重漏洞,就會阻止後續的 pull 操作,避免有漏洞的映像檔被部署到環境中。

常見問題與風險

  • 誤報疲勞(Alert Fatigue from False Positives):掃描工具報了 200 個漏洞,其中 150 個在你的使用場景下根本不會被觸發(例如某個 CVE 只影響特定的函式呼叫路徑,但你沒有用到那個函式)。團隊花大量時間評估每個 CVE 是否真的有影響,最後疲勞了開始忽略所有掃描結果——這比不掃描更危險,因為你會產生「我們有做安全掃描」的虛假安全感。應對方式:使用 .trivyignore 檔案記錄經過評估確認為誤報的 CVE,附上評估原因和評估日期,定期 review 這個清單。只對 CRITICAL 和 HIGH 等級設定阻擋,Medium 和 Low 用報告追蹤即可。

  • Base Image 的漏洞不歸你管但要你修:你用了 node:20-alpine,掃描出 Alpine 的 libcrypto 有 CVE。你能做的只有等上游釋出修補版本然後重新 build。但如果上游遲遲不修,你的 pipeline 就一直過不了。應對方式:選擇更新頻繁的 base image(如 Chainguard Images、Google Distroless);設定 --ignore-unfixed 忽略沒有修復版本的漏洞;定期重新 build 映像檔以取得最新的安全更新。

  • 掃描讓 CI 變慢:Trivy 第一次掃描需要下載漏洞資料庫(約 30-50MB),加上掃描本身可能需要 30 秒到 2 分鐘。如果每次 push 都做完整掃描,CI 時間會顯著增加。應對方式:在 CI Runner 上快取 Trivy DB(設定 TRIVY_CACHE_DIR 並用 GitLab cache 保存);非 main branch 的 MR 只做 dependency scan(快),main branch 和 tag 才做完整 image scan(慢);或者把 image scan 改成 allow_failure: true,不阻擋 pipeline 但產出報告。

  • 供應鏈攻擊防不勝防:掃描工具只能找到「已知漏洞」(已被揭露並有 CVE 編號的)。零時差漏洞、惡意維護者故意植入的後門(如 xz-utils 事件)、typosquatting(惡意套件名稱和知名套件只差一個字母),這些掃描器都抓不到。應對方式:鎖定依賴版本(使用 lock file);啟用 npm 的 --ignore-scripts 避免安裝時自動執行惡意腳本;使用 Socket.dev 等新一代工具分析套件行為而非只看已知 CVE。

  • 不同工具掃出來的結果不一致:Trivy 說有 50 個漏洞、Snyk 說有 30 個、GitLab built-in 說有 70 個。每個工具用的 CVE 資料庫來源、版本偵測邏輯、嚴重程度評分都不完全相同。團隊不知道該信哪個。應對方式:選定一個工具作為 single source of truth,其他工具的結果作為參考。建議以 Trivy 為主(開源、更新快、社群活躍),搭配 Snyk 的自動修復 PR 功能作為補充。

  • License 合規問題被忽略:團隊專注在漏洞掃描,忽略了授權合規。專案裡用了 GPL-3.0 的套件但沒有開源自己的程式碼,直到收到律師函才發現問題。應對方式:在 CI pipeline 裡加入 SCA 掃描(Trivy 的 --scanners license 或專門的 SCA 工具),建立團隊的授權白名單(例如只允許 MIT、Apache-2.0、BSD),有 copyleft 授權的套件需要經過技術主管核准才能使用。

小結

安全掃描不是裝了工具就萬事大吉——它需要融入開發流程才有效果。在 IDE 裡裝 linter 抓硬編碼密碼、在 CI 裡用 Trivy 掃依賴和映像檔、在 Harbor 裡設定自動掃描和漏洞阻擋、在 staging 環境跑 DAST。每一層都是一道防線,任何一道防線漏掉的東西都有機會被下一道攔住。最重要的是團隊文化:安全不是安全團隊的專屬責任,每個開發者都應該在 npm install 一個新套件時想一下——這個套件有多少人在維護?上次更新是什麼時候?它需要什麼權限?這種意識加上自動化工具,才是真正有效的安全策略。


延伸閱讀