新發布SkillSec:把 Skills 安全從惡意檢測,升維到能力審計SkillSec瞭解更多 →
技術解讀

容器鏡像的成分分析:比源碼掃描多出來的那幾層

安勢研究院··2 分鐘閲讀
容器鏡像的三層組件結構與掃描覆蓋範圍
容器鏡像的三層組件結構與掃描覆蓋範圍

一個常見的困惑

團隊把 SCA 接進了 CI,源碼掃描乾乾淨淨,結果安全團隊用鏡像掃描器一掃,報出幾十個高危漏洞。開發的第一反應通常是「掃描器有問題」。

掃描器沒問題。兩邊掃的根本不是同一個東西。

鏡像裏到底有什麼

一個典型的應用鏡像包含三層性質不同的組件:

第一層:基礎鏡像(OS 層)——你在 Dockerfile 第一行寫的 FROM。它帶來一整個操作系統的用户空間:glibc、openssl、bash、coreutils、包管理器本身。這一層的組件數量通常遠超應用依賴,而且完全不在任何應用清單文件裏。

第二層:系統包——構建過程中 apt-get installapk add 裝進去的東西:curl、git、編譯工具鏈、各種運行時庫。它們經常是為了構建而裝、裝完忘了刪,最終留在生產鏡像裏。

第三層:語言依賴——package.jsonpom.xmlrequirements.txt 裏聲明的那些。這一層,也只有這一層,是源碼 SCA 能看到的。

所以「源碼掃描乾淨但鏡像有漏洞」根本不矛盾:問題出在你沒寫、但確實在運行的那兩層裏。

為什麼基礎鏡像是風險重災區

基礎鏡像的問題不在於它質量差,而在於三個結構性因素:

體積即攻擊面。 一個完整的 ubuntu:22.04 帶着幾百個包,其中絕大多數你的應用根本用不到——但它們的漏洞照樣會被掃出來,照樣需要你解釋或修復。

更新滯後。 FROM node:18 這樣的寫法看似鎖定了版本,實際上標籤是浮動的,而團隊往往幾個月才重建一次鏡像。基礎鏡像的安全更新不會自動到達你的生產環境。

繼承的不可見性。 你的鏡像 FROM 了某個團隊的中間鏡像,那個鏡像又 FROM 了別的。最終生產鏡像裏的組件,可能來自三四層之外的某個決定,而沒有人完整地看過這條鏈。

三條治理原則

一、選擇精簡且有維護承諾的基礎鏡像。

distroless、官方 slim 變體、alpine——選擇的核心不是「哪個最小」,而是「哪個在滿足運行需求的前提下組件最少,且有明確的安全更新節奏」。少一個包就少一個潛在的 CVE 和一次不必要的解釋。

二、鏡像掃描進 CI,與源碼掃描並行。

兩者互補而非替代:源碼 SCA 在依賴引入時攔截(更早、修復成本更低),鏡像掃描在交付物層面兜底(更全、覆蓋你沒聲明的部分)。理想的門禁位置是鏡像構建之後、推送到倉庫之前——此時還能重建,推上去再發現就是回滾了。

三、基礎鏡像版本全公司統一管理。

不是每個團隊各自選 FROM,而是公司維護一組經過安全審查的基線鏡像,各團隊從基線派生。這樣做的收益在漏洞爆發時最明顯:修一次基線,所有下游重建即可,而不是二十個團隊各查各的。

SBOM 應該覆蓋到哪一層

如果你要給客户或監管提交容器化產品的 SBOM,只導出語言依賴是不夠的——收方期待的是「這個鏡像裏有什麼」,而不是「這個應用聲明瞭什麼」。

完整的容器 SBOM 應當包含:基礎鏡像標識與摘要、系統包清單(含版本)、語言依賴樹、以及各層的來源信息。好在這件事是可自動化的:在 CI 裏對構建產出的鏡像做一次成分分析,導出 SPDX 或 CycloneDX,隨鏡像一起發佈。

需要留意的是層的可追溯性:同一個組件可能出現在多個層,來源不同、修復路徑也不同。基礎鏡像裏的 openssl 要靠換基礎鏡像修,應用依賴裏的要靠改依賴聲明修——SBOM 如果不區分來源,收到的人無法判斷該找誰修。

從「掃描通過」到「成分清楚」

容器化把交付物從「一個 jar 包」變成了「一整個運行環境」,這讓軟件供應鏈的邊界向下擴展了兩層。相應地,成分透明的要求也必須跟着下沉。

值得強調的是:這不只是安全問題,也是許可證問題。基礎鏡像裏的 GPL 組件、系統包的許可證義務,同樣會隨着鏡像分發而傳遞。只看應用依賴的合規審計,在容器化交付面前是不完整的。

---

延伸閲讀SBOM 字段實操指南 · 在 CI 流水線裏配置 SCA 門禁 · CleanSource SCA 的容器鏡像分析能力

容器安全鏡像掃描SBOM基礎鏡像SCADevSecOps供應鏈安全
想看看這些能力在你的代碼庫上如何落地?預約演示

相關閲讀

技術解讀

SBOM 不止是合規清單:從「我用了什麼」到「我能承受什麼」

很多團隊把 SBOM 當成一份交差用的清單。但真正有價值的 SBOM,是能驅動決策的:哪些漏洞可被利用、哪條依賴該先修、哪個許可證會帶來風險。