第 238 章:审计与合规实战
学习目标
- 审计日志设计
- 满足等保 / GDPR / PCI-DSS
- 应急响应流程
- 安全合规检查
一、合规体系总览
二、审计日志设计
2.1 审计要素
java
@Data
@Entity
@Table(name = "audit_log")
public class AuditLog {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String service; // 服务名
@Column(nullable = false)
private String action; // 操作类型
@Column(nullable = false)
private String resource; // 操作资源
@Column(nullable = false)
private String userId; // 用户 ID
@Column(nullable = false)
private String ip; // IP
@Column(columnDefinition = "TEXT")
private String params; // 参数(脱敏后)
@Column(nullable = false)
private String status; // SUCCESS / FAILURE
@Column(length = 4000)
private String errorMessage; // 异常信息
@Column(nullable = false)
private Instant timestamp; // 时间
}2.2 审计 Facade
java
@Component
public class AuditLogger {
@Autowired
private AuditLogRepository repo;
@Autowired
private ObjectMapper mapper;
@Autowired
private DesensitizationService desens;
public void log(String action, String resource, Object params, Throwable error) {
try {
AuditLog log = new AuditLog();
log.setService(getCurrentServiceName());
log.setAction(action);
log.setResource(resource);
log.setUserId(UserContextHolder.getUserId());
log.setIp(RequestUtil.getClientIp());
log.setParams(desens.desensitize(
params != null ? mapper.writeValueAsString(params) : null
));
log.setStatus(error == null ? "SUCCESS" : "FAILURE");
log.setErrorMessage(error != null ? error.getMessage() : null);
log.setTimestamp(Instant.now());
repo.save(log);
} catch (Exception e) {
// 审计失败不影响业务
log.error("审计失败", e);
}
}
public void log(String action, String resource, Object params) {
log(action, resource, params, null);
}
}2.3 异步写入
yaml
spring:
task:
execution:
pool:
audit:
core-size: 4
max-size: 8
queue-capacity: 1000java
@Async("auditExecutor")
public void logAsync(...) { ... }或批量刷盘:
java
@Component
public class AuditBuffer {
private final BlockingQueue<AuditLog> queue = new LinkedBlockingQueue<>(10000);
@PostConstruct
public void flushThread() {
new Thread(this::drain).start();
}
private void drain() {
List<AuditLog> batch = new ArrayList<>(1000);
while (true) {
try {
AuditLog log = queue.take();
batch.add(log);
queue.drainTo(batch, 999);
if (!batch.isEmpty()) {
repo.saveAll(batch);
batch.clear();
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
}2.4 审计 Trace 串联
java
@Component
public class AuditLogAspect {
@Autowired
private AuditLogger logger;
@Around("@annotation(auditAnnotation)")
public Object audit(ProceedingJoinPoint pjp, Audit auditAnnotation) throws Throwable {
String action = auditAnnotation.action();
String resource = pjp.getSignature().getDeclaringTypeName();
try {
Object result = pjp.proceed();
logger.log(action, resource, pjp.getArgs());
return result;
} catch (Throwable t) {
logger.log(action, resource, pjp.getArgs(), t);
throw t;
}
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Audit {
String action();
}
@Audit(action = "ORDER_CREATE")
public Order createOrder(OrderRequest req) { ... }2.5 审计查询界面
sql
-- 7 日内某用户的操作
SELECT * FROM audit_log
WHERE user_id = ? AND timestamp > NOW() - INTERVAL 7 DAY
ORDER BY timestamp DESC;
-- 高频异常用户
SELECT user_id, COUNT(*) cnt
FROM audit_log
WHERE status = 'FAILURE' AND timestamp > NOW() - INTERVAL 1 HOUR
GROUP BY user_id HAVING cnt > 20;三、GDPR / 个人信息保护法
3.1 合规要求
yaml
告知: 明确告知用途
同意: 主动勾选
最小: 数据不得过度收集
使用目的限制: 只能用收集用途
可见: 用户可查询自己数据
可携: 用户可导出
删除: 用户可被遗忘
安全: 防泄露
响应: 72 小时内报告违规3.2 同意管理
sql
CREATE TABLE consent (
user_id BIGINT,
purpose VARCHAR(50), -- analytics / marketing / essential
granted BOOLEAN,
granted_at TIMESTAMP,
ip_address VARCHAR(45)
);java
@Service
public class ConsentService {
public void grantConsent(Long userId, Purpose purpose, String ip) {
// 记录同意 + IP + 时间,作为证据
consentRepo.save(new Consent(userId, purpose, true, Instant.now(), ip));
}
public boolean isAllowed(Long userId, Purpose purpose) {
return consentRepo.findById(new ConsentKey(userId, purpose))
.map(Consent::isGranted)
.orElse(false);
}
}3.3 数据最小化
java
@Entity
@Table(name = "user") // 敏感字段加密存储
public class User {
@Column(nullable = false)
private String username;
@Convert(converter = EncryptedStringConverter.class)
private String phone; // 加密
@Convert(converter = EncryptedStringConverter.class)
private String idCard; // 加密
private String city; // 不存详细地址
}3.4 用户数据访问
java
@RestController
@RequestMapping("/api/privacy")
public class PrivacyController {
@GetMapping("/my-data")
public UserDataExport exportMyData(Long userId) {
UserDataExport export = new UserDataExport();
export.setUser(userRepo.findById(userId));
export.setOrders(orderRepo.findByUser(userId));
export.setLoginHistory(auditRepo.findLoginsByUser(userId));
// 生成下载链接,72 小时过期
String url = fileService.upload(JSON.toJSONString(export));
return new UserDataExport(url);
}
@DeleteMapping("/my-account")
public void deleteMyAccount(Long userId) {
// 1. 软删除
userService.softDelete(userId);
// 2. 触发链式删除
kafkaTemplate.send("user-events", new UserDeletedEvent(userId));
}
}四、等保 2.0 合规
4.1 五级要求
| 等级 | 适用 |
|---|---|
| 第一级(自主) | 一般系统 |
| 第二级(指导) | 一般业务 |
| 第三级(监督) | 重要业务(金融、政务、电信) |
| 第四级(强制) | 极重要 |
| 第五级(专控) | 涉密 |
4.2 三级系统要求
yaml
物理:
- 机房电磁屏蔽
- 视频监控
- 防雷击
网络:
- 划分安全区域
- 网络隔离
- NTP 时间同步
主机:
- 操作系统加固
- 漏洞补丁
- 入侵检测
应用:
- 用户认证
- 访问控制
- 数据加密
- 安全审计
数据:
- 数据加密
- 备份恢复
- 完整性校验4.3 技术要求
4.4 等保整改项
| 维度 | 整改 |
|---|---|
| 访问控制 | RBAC + 强密码 + MFA |
| 审计 | 集中日志,180 天保留 |
| 入侵防范 | WAF + 主机 HIDS |
| 恶意代码防范 | 防病毒 + 镜像扫描 |
| 数据保密 | 加密存储 + 加密传输 |
| 数据备份 | 3-2-1 备份 |
| 漏洞修复 | 7 天内紧急漏洞 |
五、PCI-DSS
金融支付卡合规。
yaml
12 项要求:
1. 安装维护防火墙
2. 不使用厂商默认配置
3. 持卡人数据保护
4. 加密传输
5. 防病毒软件
6. 维护安全系统
7. 按需访问权限
8. 唯一身份标识
9. 物理安全
10. 监控 + 测试
11. 定期评估
12. 信息安全政策关键:
- CDE(持卡人数据环境)隔离
- 不存 CVV / PIN
- 加密存储 PAN
六、应急响应
6.1 事件分类
| 级别 | 示例 |
|---|---|
| P0 | 大规模数据泄露 |
| P1 | 系统被入侵 |
| P2 | 漏洞被发现 |
| P3 | 异常行为告警 |
6.2 响应流程
6.3 取证要点
yaml
时间线: 用 NTP 同步的时钟
原始证据: dd 命令镜像磁盘
日志保留: Web/DB/应用/中间件
文件 hash: 留 integrity 校验
内存 dump: vmstat / memdump / Volatility
网络: tcpdump,IP 记录6.4 通知合规要求
yaml
GDPR:
- 72 小时内通知监管
- 用户高风险时也要通知
中国数据安全法:
- 立即向监管部门报告
- 重大事件向社会发布七、合规检查清单
7.1 等保 三级 自查
yaml
✓ 机房 / 物理安全
✓ 网络架构合理划分
✓ 网络设备配置基线
✓ 操作系统加固
✓ 数据库配置基线
✓ 应用最小权限
✓ 身份认证(MFA)
✓ 访问控制(RBAC)
✓ 审计日志 ≥ 180 天
✓ 数据加密(传输 + 存储)
✓ 入侵检测/防御
✓ 漏洞修复 ≤ 7 天
✓ 备份演练
✓ 应急预案
✓ 安全管理机构
✓ 人员安全7.2 应用层安全自查
yaml
检查点:
- SQL 注入:参数化查询
- XSS:输出转义
- CSRF:Token 校验
- SSRF:URL 白名单
- 越权:RBAC + 资源校验
- 弱密码:策略强制
- 密钥管理:Vault
- 日志:不记敏感信息
- 异常处理:不泄露堆栈
- 依赖漏洞:SCA 扫描
- HTTPS:全站启用
- HSTS:启用7.3 工具化检查
bash
# 依赖漏洞
trivy fs ./
snyk test
# 镜像扫描
trivy image myapp:1.0
# 端口扫描
nmap -sV myhost.example.com
# 配置检查
nuclei -u https://myapp.example.com八、第三方与供应商
8.1 风险评估
yaml
评估维度:
- 数据访问范围
- 技术能力
- 安全资质(ISO 27001 / SOC 2)
- 历史安全事件
- 合同条款8.2 数据处理协议(DPA)
yaml
必备条款:
- 数据处理目的与方式
- 安全义务
- 保密义务
- 数据主体权利响应
- 子处理者管理
- 数据销毁
- 审计权
- 违约责任
- 跨境传输8.3 风险监控
yaml
定期评估: 至少每年一次
现场审计: 关键供应商
合规报告: SOC 2 / ISO
事件通知: 24 小时内通报九、用户隐私体验
9.1 隐私政策
yaml
必备内容:
- 数据收集清单
- 数据使用目的
- 数据共享第三方
- 数据存储期限
- 用户权利
- 联系方式
- 更新通知9.2 Cookie 同意横幅
html
<div id="cookie-banner">
我们使用 Cookie 提供服务,继续浏览视为同意。
<a href="/privacy">隐私政策</a>
<button id="accept">同意</button>
<button id="reject">拒绝</button>
</div>9.3 隐私设计(PbD)
yaml
七原则:
1. 预防(Proactive not Remediation)
2. 默认隐私(Privacy as Default)
3. 嵌入设计(Privacy Embedded)
4. 全功能(Positive-Sum, not Zero-Sum)
5. 端到端安全(End-to-End Security)
6. 可见透明(Visibility and Transparency)
7. 用户尊重(Respect for User Privacy)十、本章小结
| 主题 | 关键 |
|---|---|
| 审计 | 集中日志 + 不可篡改 + 长期保留 |
| GDPR | 数据最小 + 同意 + 被遗忘 |
| 等保 2.0 | 技术 + 管理 双体系 |
| PCI-DSS | CDE 隔离 + 不存 PAN |
| 应急 | 取证 + 通知 + 复盘 |
动手练习
- 实现审计日志系统,记录所有敏感操作
- 给你的 API 加 RBAC + 资源访问检查
- 写数据导出接口,用户可下载自己的数据
- 配置审计日志保留 180 天,异地归档