完整性保护的基本概念与原理
聊审计日志完整性,得先搞清楚「完整性」到底指什么。
我入行头两年,总把完整性和机密性混为一谈。后来在金融项目里吃过亏才明白——完整性保证的是数据没被改过,机密性保证的是数据没被别人看到。你想想看,日志被人偷看了,顶多算泄密;但如果日志被人改了,那整个审计链条就断了,谁也说不清发生了什么。
2.1 完整性的核心定义
说白了,完整性就是三个字——没动过。具体到审计日志:
- 内容没被篡改(新增、删除、修改都算)
- 顺序没被打乱(时间戳和序号必须匹配)
- 来源可追溯(谁写的、什么时候写的、用哪个设备写的)
嗯,这里要注意:日志完整性不是二进制层面的一模一样。比如日志轮转、格式转换这些合法操作,只要保留了原始记录的摘要,完整性就没丢。
我在项目中遇到过一个问题:客户要求保留日志90天,但存储不够。运维就偷偷把旧日志压缩了。压缩本身没改内容,但解压后时间戳乱掉了。后来我加入了一条规则:任何存储格式转换都必须保留原始哈希摘要。
2.2 审计日志完整性为什么重要?
原因其实就一个——你没法信任一个可能被改过的证据。
我记得有一次做安全事件复盘,攻击者删掉了自己的登录记录。如果没有完整性保护,那日志就成了废纸。合规审计里常说「非否认性」,其实就是建立在完整性之上的。
下面这张表可以快速对比:
| 属性 | 含义 | 日志场景举例 |
|---|---|---|
| 完整性 | 数据未被未授权修改 | 日志条目哈希值匹配 |
| 机密性 | 数据未泄露给未授权方 | 日志传输或存储加密 |
| 可用性 | 数据在需要时可访问 | 日志备份、容灾恢复 |
| 真实性 | 数据来源可验证 | 数字签名验证日志来源 |
2.3 核心保护原理
完整性保护不是一种技术,而是一套组合拳。我建议你从三个层面理解:
2.3.1 检测层:哈希与数字签名
每次写入日志时,计算整条记录的哈希值,再用私钥签名。验证时你拿公钥验签,哈希一比对就知道有没有被改过。
避坑指南:我曾经在项目中直接用MD5做完整性校验,后来发现MD5冲突攻击已经足够威胁日志安全。现在强制用SHA-256及以上。
2.3.2 防删除层:链式结构与时间戳
单条日志的哈希好做,但攻击者把整条日志删掉怎么办?链式结构就解决了这个问题——前一条日志的哈希会混入后一条日志的计算。你删其中一条,整个链条对不上,立马暴露。
// 伪代码示例:日志链哈希计算
prevHash := getPreviousLogHash()
currentLog := {timestamp, event, user, prevHash, nonce}
currentHash := SHA256(currentLog)
// 存储 currentLog + currentHash
2.3.3 不可抵赖层:可信时间戳与持久化
光有链还不够,时间戳必须是可信的(比如NTP同步或硬件安全模块)。另外,日志要持久化到不可更改的介质,比如WORM存储(一次写入多次读取)。
2.4 威胁模型
知道原理后,咱们得想想攻击者会从哪下手。我总结了几种常见场景:
- 篡改现有记录 —— 直接改内容、改时间
- 删除整条记录 —— 尤其是不法操作前后的日志
- 插入虚假记录 —— 比如伪造一条“系统故障”掩盖入侵
- 重放旧记录 —— 用过去合法的日志覆盖现在的
- 破坏链式完整性 —— 找到链式结构的弱点,比如哈希碰撞
重要提醒:攻击者不一定直接碰日志文件。他们可能先拿到日志服务器的root权限,然后修改完整性校验程序本身。所以保护日志完整性的同时,也要保护保护日志的系统。
2.5 常见保护机制一览
下面这张图展示了审计日志完整性保护的核心流程,也是我个人习惯用的设计框架:
我自己的习惯是,先画清楚上面这个流程,再考虑每个环节的技术选型。比如哈希可以用SHA-256,签名可以用RSA-2048,存储层可以考虑用区块链的思路(但别搞复杂了)。
特别说一下:签名和链式存储不是互斥的。我建议两个都用——签名保证单条记录没被改,链式保证删除或重排序立刻暴露。你问我为什么?有一次项目里只用链式没做签名,结果攻击者通过日志服务器漏洞替换了整个日志文件。链还在,但根哈希被改了,我根本发现不了。后来我加了一层签名,才彻底堵住这个坑。
2.6 你思考一下
为什么很多审计框架(比如PCI-DSS、SOX)都要求「日志不可更改」?其实就是因为我们上面讲的这些东西——没有完整性保护,审计就是自欺欺人。