乐于分享
好东西不私藏

第十七期:软件和数据完整性失败(Software and Data Integrity Failures)· 理论篇

第十七期:软件和数据完整性失败(Software and Data Integrity Failures)· 理论篇

前言

2020年12月,全球最大的软件供应链攻击震惊了整个安全行业。

攻击者入侵了 SolarWinds 的 CI/CD 管道,在官方签名的 Orion 更新包中植入了 Sunburst 后门程序。这个更新包经过了合法的数字签名,通过了 SolarWinds 官方的发布流程,推送到了约 18,000 家企业和政府机构。FireEye(现Mandiant)、Microsoft、VMware、Cisco 等顶级科技公司纷纷中招,美国国土安全部、财政部、商务部全面沦陷。

这一切发生的前提只有一个:软件供应链的完整性验证机制存在缺陷

这是 OWASP Top 10 2021 中 A08: Software and Data Integrity Failures(软件和数据完整性失败)的典型案例。此类别在 2017 版中并未独立出现,它是将不安全的反序列化、CI/CD 供应链问题、不安全的自动更新等零散漏洞整合为一个统一的攻击面——攻击者不再需要正面攻破你的系统,只需要攻破你信任的源头


一、为什么软件和数据完整性是安全问题

1.1 信任链与完整性验证的本质

现代软件系统的运行,建立在一系列隐式信任假设之上:

用户程序
    ↓ 依赖
第三方库(Maven/ npm / PyPI)
    ↓ 依赖
基础镜像(Docker Hub / 公共仓库)
    ↓ 来源
自动更新服务
    ↓ 来源
CI/CD 管道(代码提交 → 构建 → 测试 → 发布)

每一层都默认上游提供的内容是可信的、完整的、未被篡改的。一旦某个环节的完整性验证缺失或不足,攻击者就可以从最薄弱的信任节点发起攻击,而下游所有依赖方全部沦陷。

1.2 完整性保护的三要素

要素
定义
失效后果
真实性(Authenticity)
我收到的内容确实来自我所认为的那个来源
攻击者伪装成合法发布者
完整性(Integrity)
内容在传输/存储过程中未被篡改
恶意代码被植入合法软件包
可用性(Availability)
完整性验证不妨碍正常业务流程
安全机制被滥用导致 DoS

1.3 从 SolarWinds 看软件供应链攻击链

攻击链分析:

Phase1: CI/CD 入侵
    攻击者通过密码喷洒(Password Spraying)获得 SolarWinds 内部 VPN 凭证
    访问内部 Exchange 服务器,发现 Orion 平台构建系统权限配置不当
    ↓

Phase 2: 代码注入
    在 Orion 源代码中植入 Sunburst 后门(隐藏在合法的类/函数中)
    构建系统使用被污染的源码打包成更新包
    ↓

Phase 3: 签名绕过
    SolarWinds 的代码签名流程存在缺陷:
    签名发生在构建之后,但构建过程本身未被监控
    攻击者的代码在签名后才被插入(build re-injection)
    ↓

Phase 4: 恶意更新分发
    受污染的更新包通过官方渠道推送,附有合法数字签名
    自动更新机制无完整性强校验,直接安装
    ↓

Phase 5: 横向移动(后渗透)
    Sunburst 后门建立 C2 通信,窃取凭证,横向移动
    部分目标被进一步部署了 TEARDROP / RAINDROP 等二次攻击工具

为什么传统安全设备无法检测:

  • 更新包有合法签名 → SSL/TLS 加密传输 → 内容加密 → WAF/IDS 看不到
  • 后门代码与合法代码混淆 → 静态扫描无法识别
  • C2 通信伪装成正常 DNS 查询 → 防火墙放行

二、软件和数据完整性失败的分类

2.1 不安全的反序列化(Insecure Deserialization)

原理:

序列化是将对象转换为字节流的过程(便于存储或传输),反序列化是将字节流还原为对象的过程。许多编程语言内置序列化机制,开发者经常反序列化来自不可信来源的数据。

风险所在:

反序列化不仅仅是"还原数据",在某些语言中,它会触发对象构造、getter/setter 等副作用。如果反序列化过程中触发了危险方法(如 Java 的 readObject、Python 的 __reduce__),攻击者可以通过构造特定的序列化 payload,在反序列化时执行任意代码。

Python pickle 反序列化示意(原理层面):

# pickle.loads() 从不可信数据恢复对象
# 如果对象定义了 __reduce__,反序列化时会自动调用
import pickle

classMalicious:
def__reduce__(self):
# 反序列化时执行:os.system('id > /tmp/pwned')
import os
return (os.system, ('id > /tmp/pwned',))

# 攻击者序列化这个对象
malicious_data = pickle.dumps(Malicious())

# 受害者反序列化,代码即执行
pickle.loads(malicious_data)  # RCE!

OWASP 分类依据:

反序列化漏洞的危害极大(通常直接 RCE),但利用条件相对复杂(需要目标使用特定序列化库+接受不可信输入)。在 2017 版 OWASP 中曾与注入合并,在 2021 版中部分归入 A08。


2.2 不安全的 CI/CD 管道(Insecure CI/CD Pipeline)

攻击面分析:

CI/CD 管道是现代软件交付的核心,通常包括:代码提交 → 静态扫描 → 构建 → 单元测试 → 集成测试 → 制品签名 → 镜像推送 → 部署。

每个环节都是潜在的攻击面:

环节
风险
真实案例
代码提交
恶意代码混入正规提交
GitHub Actions 供应链攻击(2021)
依赖引入
依赖库被劫持或投毒
PyPI event-stream 投毒(2018)
构建系统
构建脚本被篡改,产物被植入后门
SolarWinds Orion(2020)
镜像仓库
拉取被污染的基础镜像
Homebrew curl 投毒(2021)
签名流程
签名密钥泄露或签名环节被绕过
ASUS 签名证书泄露(2019)
部署配置
Kubernetes YAML 被篡改,部署恶意容器
Tesla K8s 挖矿事件(2018)

CI/CD 管道攻击的独特危害:

  1. 放大效应
    :一次成功的 CI/CD 攻击,可以自动扩散到所有使用该产品的客户
  2. 信任滥用
    :恶意内容通过了所有安全检查流程(因为安全检查本身也被攻击者利用)
  3. 持久化
    :后门被嵌入在定期更新的软件中,可以长期潜伏

2.3 不安全的自动更新机制(Insecure Auto-Update)

原理:

软件应用的自动更新功能,通常遵循以下流程:

检查更新服务器 → 下载更新包 → 验证版本号 → 安装

如果完整性验证缺失或不足:

缺陷场景
攻击方式
只验证版本号,不验证签名
攻击者搭建仿冒更新服务器,推送高版本恶意更新
签名验证使用硬编码公钥
公钥泄露后,攻击者可签署任意版本
通过 HTTP 下载更新包(无 TLS)
中间人攻击注入恶意更新包
更新包放在可写的 NFS/SMB 共享上
本地攻击者直接替换更新包

真实案例: Notepad++ 供应链事件(2017):

攻击者入侵了 Notepad++ 的 SourceForge 文件分发账户,将官方安装包替换为植入木马的版本。虽然最终因数字签名不匹配被部分安全软件拦截,但事件暴露了分发环节的完整性验证缺失问题。


2.4 依赖来源不验证(Reliance on Untrusted Data Without Integrity Check)

核心问题:

应用程序经常需要:

  • 从 CDN 加载 JavaScript 库
  • 从外部 API 获取配置数据
  • 从插件市场安装扩展
  • 从配置文件读取序列化数据

如果这些外部数据没有完整性验证(数字签名/哈希校验),攻击者可以通过以下方式实施攻击:

攻击向量分类:

外部数据来源 → 攻击方式
─────────────────────────────────────────────
CDN 劫持(路由投毒/DNS 劫持)→ 替换 JS 库为恶意版本
    → 后果:XSS 窃取 Cookie、键盘记录、页面注入

API 响应无签名验证 → 中间人篡改 API 响应
    → 后果:业务逻辑被绕过、敏感数据被篡改

插件市场账户被入侵 → 发布含后门的插件更新
    → 后果:RCE 或数据窃取

序列化数据无完整性校验 → 反序列化攻击(见 2.1)
    → 后果:RCE

第三方配置文件被篡改 → 注入恶意配置改变应用行为
    → 后果:权限提升、认证绕过

特别警示:

2021 年,攻击者通过抢注 PyPI 弃用包名称(Typosquatting),发布了 requests(正确包名)的伪造版本 requesetsrequestrequeset 等,成功骗取开发者的 pip 安装。这些伪造包包含窃取环境变量的代码,在 CI/CD 管道中自动执行。


2.5 序列化数据的完整性失败

除了 2.1 中讨论的反序列化 RCE,更广泛的序列化数据完整性问题还包括:

Cookie / Session 篡改:

某些应用将敏感数据序列化后存储在 Cookie 或 localStorage 中,客户端可以通过修改序列化数据绕过业务逻辑(如修改 role: "user" 为 role: "admin")。

JWT 签名绕过:

JSON Web Token 如果使用了 alg: none(无签名)或使用了弱算法(如 HS256 但使用公开知道的公钥作为密钥),攻击者可以伪造任意权限的 JWT。

配置文件注入:

应用读取 YAML/JSON 配置文件时,如果配置文件来源不可信且缺乏 Schema 校验,攻击者可以通过注入恶意配置(如 SpEL 表达式、模板注入、JNDI 引用)实现代码执行。


三、真实案例深度解析

3.1 Equifax 数据泄露与 Apache Struts 反序列化(2017)

事件背景:

Equifax 是美国三大信用报告机构之一。2017年9月,宣布发现了一起影响 1.47 亿人的数据泄露事件。攻击者利用 Apache Struts 2 的 CVE-2017-5638(S2-045)远程代码执行漏洞,窃取了姓名、SSN、出生日期、地址、驾驶证号码、信用卡号等敏感数据。

漏洞原理(技术层面):

Apache Struts 2 的 Jakarta Multipart Parser 在处理 Content-Type 头时存在漏洞。攻击者可以通过构造恶意的 Content-Type 头,注入 OGNL 表达式,在服务器端执行任意代码:

Content-Type: %{(#_='multipart/form-data').(#[#context:['com.opensymphony.xwork2.dispatcher.HttpServletResponse']].addHeader('X',...)}}

OGNL 表达式在处理时被 Struts 2 的过滤器解析,攻击者可以借此执行系统命令。

数据完整性失败的维度:

  • 反序列化层面
    :Struts 2 使用 OGNL 表达式解析用户输入,OGNL 反序列化过程中触发代码执行
  • 输入验证层面
    :Content-Type 头本不应该被用作表达式求值,但 Struts 2 错误地将用户输入传递给了 OGNL 引擎
  • 补丁验证层面
    :Apache 在 2017 年 3 月已发布 S2-045 修复补丁,但 Equifax 直至 5 月仍未打补丁(补丁验证机制缺失)

损失:

  • 约 1.47 亿用户数据泄露
  • 集体诉讼赔偿 7 亿美元
  • CEO、CSO 辞职
  • FTC 罚款 5.75 亿美元

3.2 event-stream npm 包投毒事件(2018)

事件背景:

event-stream 是一个广泛使用的 Node.js 工具库(每周下载量超过百万)。攻击者通过 GitHub 建立了对该项目的信任后,向 npm 提交了代码捐赠,将自己的账户添加为 event-stream 的维护者之一。

攻击过程:

攻击者联系 event-stream 原作者,提出代码捐赠
    ↓
原作者将 npm 发布权限转让给攻击者
    ↓
攻击者发布 event-streamv3.3.6,在依赖中添加 flatmap-stream@0.1.1
    ↓
flatmap-stream 包含恶意代码:窃取比特币钱包私钥
    ↓
大量 Node.js 应用(包括 Copay 比特币钱包)自动安装了带毒版本
    ↓
Copay 用户的比特币私钥被窃取

数据完整性失败的维度:

  • 供应链信任
    :npm 的代码捐赠机制缺乏安全性审核,没有验证新维护者的真实身份
  • 依赖完整性
    :event-stream v3.3.6 的 package.json 中引入了一个看似无害的 flatmap-stream 依赖,没有人会想到这会是一个专门窃取比特币钱包的后门
  • 版本锁定缺失
    :大多数项目使用 ^3.3.4 这样的宽松版本范围,自动接受了 3.3.6 恶意更新

3.3 Homebrew GitHub Actions 供应链攻击(2021)

事件背景:

Homebrew 是 macOS 最流行的包管理器。2021年4月,一名攻击者利用 GitHub Actions 的自动化流程漏洞,向 Homebrew 的 Homebrew-core 仓库提交了一个恶意 GitHub Actions 工作流。

攻击方式:

攻击者向 Homebrew-core 仓库提交代码贡献(正常流程)
    ↓
代码贡献通过审查后,被合并到主分支
    ↓
GitHub Actions 自动触发 brew bump-formula-pr 工作流更新版本
    ↓
攻击者在工作流中注入恶意代码:提取 GitHub Actions secret 和 API 令牌
    ↓
以 Homebrew 官方 GitHub 机器人身份执行,权限极大

关键问题:

Homebrew 的 GitHub Actions 工作流使用了被攻击者控制的工作流触发条件(pull_request_target),使得攻击者的代码可以在 Homebrew 官方 GitHub token 的上下文中执行,从而窃取仓库权限。


四、软件和数据完整性失败的危害评估

4.1 危害等级矩阵

维度
低(1)
中(2)
高(3)
极高(4)
可利用性
需要本地访问
需要普通用户权限
可远程利用
自动化工具可用
普遍性
仅影响特定框架
影响 30% 以下应用
影响 30-70% 应用
影响 70%+ 应用
影响范围
仅影响单一实例
影响单一租户
影响整个系统
影响供应链下游所有用户
技术影响
信息泄露
权限绕过
数据篡改
远程代码执行
业务影响
轻微
中断服务
数据泄露
声誉损失 + 法律风险

4.2 为什么 A08 在 OWASP Top 10 中独立成类

整合逻辑:

2017 版 OWASP 中,不安全反序列化是 A08(注入的一部分),不安全的 CI/CD 和供应链问题没有独立分类。随着 SolarWinds、Log4Shell、event-stream 等大型供应链安全事件的频发,2021 版将这些问题整合为 A08,强调的核心观点是:

现代应用的威胁,已经从"正面攻破应用"转向"攻破应用所信任的一切"


五、防御思路概览(预告)

本期是原理与分类篇。后续两期将分别从实战利用和防御方案两个维度展开。防御方案篇将覆盖:

  • CI/CD 管道安全审计与加固
  • 软件签名与完整性验证最佳实践
  • 依赖安全审计(SBOM + 依赖扫描)
  • 自动更新安全架构设计
  • 序列化安全的全面解决方案

📚 参考框架

标准/框架
相关内容
OWASP Top 10 2021
A08: Software and Data Integrity Failures
NIST SSDF
Protect the Software Supply Chain (PSCID)
MITRE ATT&CK
Supply Chain Compromise (S0174/S0559/S0576)
ISO/IEC 27036
供应链安全控制
SLSA Framework
Software Supply Chain Security Levels
Sigstore
开源软件签名与验证生态
SPDX / CycloneDX
软件物料清单(SBOM)标准

🛡️ 理论先行,实践跟进
⚠️ 提示:本文仅供网络安全学习研究使用。所有技术方案应在获得合法授权的范围内使用。未授权的安全测试违反中国《网络安全法》及相关法规。