直接用diffID、chainID和digest三类哈希值可离线校验镜像完整性:diffID验证层内容真实性,chainID验证层链连贯性,digest验证manifest一致性,rootfs组装校验为可选延伸。

直接用 diffID、chainID 和 digest 这三类哈希值,就能在本地完成镜像完整性校验——不需要联网、不依赖 registry,也不需要运行容器,纯离线验证即可。
查出镜像各层的 diffID 和 chainID
Docker 镜像元数据里明确记录了每层的 diffID(内容指纹)和 chainID(位置指纹)。执行以下命令可提取:
-
docker image inspect nginx:latest --format='{{json .RootFS.Layers}}'—— 输出所有 layer 的 chainID 列表 -
docker image inspect nginx:latest --format='{{json .ContainerConfig}}'或解析 config blob(通常需docker save+ 解压)才能拿到原始 diffID 数组
注意:RootFS.Layers 中的值是 chainID,不是 diffID;而 config blob 中的 rootfs.diff_ids 字段才是各层原始 diffID(格式为 sha256:xxx),它是校验层内容真实性的起点。
比对本地 layer 文件系统是否被篡改
Docker 将每一层实际内容以 tar 包解压后生成的目录树,存于 /var/lib/docker/image/overlay2/layerdb/sha256/ 下。该目录中:
-
cache-id文件记录了该层在 overlay2 存储中的实际路径 -
diff/是解压后的完整文件树 - 执行
sha256sum -b diff/**/* 2>/dev/null | sha256sum可粗略模拟 diffID 计算(需按字典序排序后拼接)
更可靠的做法是:用 tar -c -f - diff/ | sha256sum 重新打包再哈希,结果应与 config 中对应位置的 diffID 完全一致。不一致说明该层文件已被修改或损坏。
验证 chainID 链是否连贯有效
chainID 不是独立生成的,而是由上一层 chainID 和本层 diffID 推导而来:
- 第 1 层 chainID = diffID₁
- 第 2 层 chainID₂ = sha256(chainID₁ + " " + diffID₂)
- 第 3 层 chainID₃ = sha256(chainID₂ + " " + diffID₃),依此类推
你可以用 printf "%s %s" "$chainID1" "$diffID2" | sha256sum 手动验证链式关系。若某层 chainID 与计算结果不符,说明该层被替换、顺序错乱,或上层已损坏——整条链即失效,Docker 启动时会拒绝组装。
确认镜像 digest 是否匹配 manifest 内容
digest 是整个镜像的“最终身份证”,等于 manifest JSON 文件整体的 SHA256 值。要验证本地镜像:
- 先用
docker save nginx:latest -o nginx.tar导出镜像 - 解压 tar,找到
manifest.json(通常是第一个数组项里的Config和Layers字段) - 用
sha256sum manifest.json计算哈希,格式化为sha256:xxx - 对比
docker images --digests输出中该镜像对应的 digest 值
二者一致,说明 manifest 未被篡改;不一致则表明镜像元数据已损坏或被恶意替换。
运行前再验 rootfs 组装结果(可选但关键)
Docker 在容器启动前还会做最后一道校验:按 manifest 中的 layer chainID 顺序叠加所有 diff/ 目录,再计算最终 rootfs 的哈希,并与 config 中的 rootfs.type 和 rootfs.diff_ids 交叉验证。
你可用 container-structure-test 工具模拟这一步:
container-structure-test test --image nginx:latest --config test.yaml- 配置中启用
fileExistenceTests和commandTests,实质就是在验证 rootfs 组装后的真实状态
这类测试虽非底层哈希比对,但覆盖了运行时视角的完整性,是对内容寻址机制的延伸验证。











