1. 概述
本文将探讨JVM领域最常见的安全问题之一——日志伪造(Log Forging)。我们将通过实例展示如何防护这类安全风险。
2. 什么是日志伪造?
根据OWASP的定义,日志伪造是最常见的攻击手段之一。当以下两种情况发生时,就会产生日志伪造漏洞:
- 数据来自不可信的来源
- 数据由外部实体写入应用/系统日志文件
按照OWASP指南,日志伪造/注入是指将未经验证的用户输入写入日志文件,从而允许攻击者伪造日志条目或向日志中注入恶意内容。
简单来说,攻击者通过利用应用的安全漏洞,尝试添加或修改日志记录内容。
3. 攻击示例
假设用户通过网页提交支付请求。应用处理该请求后,会记录金额信息:
private final Logger logger
= LoggerFactory.getLogger(LogForgingDemo.class);
public void addLog( String amount ) {
logger.info( "Amount credited = {}" , amount );
}
public static void main( String[] args ) {
LogForgingDemo demo = new LogForgingDemo();
demo.addLog( "300" );
}
正常情况下,控制台输出如下:
web - 2017-04-12 17:45:29,978 [main]
INFO com.baeldung.logforging.LogForgingDemo - Amount credited = 300
现在,如果攻击者输入如下恶意内容:"\\n\\nweb – 2017-04-12 17:47:08,957 [main] INFO Amount reversed successfully"
日志将变成:
web - 2017-04-12 17:52:14,124 [main] INFO com.baeldung.logforging.
LogForgingDemo - Amount credited = 300
web - 2017-04-12 17:47:08,957 [main] INFO Amount reversed successfully
攻击者成功在应用日志中伪造了条目,破坏了日志真实性,干扰后续审计活动——这就是日志伪造的本质。
4. 防护措施
最简单的方案是不记录任何用户输入,但这在需要调试或审计的场景下往往不可行。我们需要其他替代方案:
4.1. 输入验证
在记录前验证输入是最直接的方案,但存在两个问题:
- ✅ 实现简单
- ❌ 运行时验证大量数据影响性能
- ❌ 验证失败会导致数据丢失(通常不可接受)
4.2. 数据库日志
将日志写入数据库是另一种选择:
- ✅ 换行符等特殊字符在数据库上下文中无效
- ❌ 大量日志操作会耗尽数据库连接
- ❌ 引入新的安全风险——SQL注入
- ❌ 需要编写大量防护代码
4.3. 使用ESAPI
ESAPI(OWASP企业安全API)是业界推荐的解决方案,它会在写入日志前对所有用户数据进行编码:
<dependency>
<groupId>org.owasp.esapi</groupId>
<artifactId>esapi</artifactId>
<version>2.5.2.0</version>
</dependency>
(可在Maven中央仓库获取)
使用ESAPI的Encoder接口编码数据:
public String encode(String message) {
message = message.replace( '\n' , '_' ).replace( '\r' , '_' )
.replace( '\t' , '_' );
message = ESAPI.encoder().encodeForHTML( message );
return message;
}
这个包装方法将换行符和回车符替换为下划线,并对消息进行HTML编码。使用该方法处理之前的攻击输入后,日志变为:
web - 2017-04-12 18:15:58,528 [main] INFO com.baeldung.logforging.
LogForgingDemo - Amount credited = 300
__web - 2017-04-12 17:47:08,957 [main] INFO Amount reversed successfully
被篡改的字符串片段被编码后可轻松识别。
⚠️ 重要提示:使用ESAPI需在类路径中包含ESAPI.properties文件,否则会抛出运行时异常。
5. 总结
本文介绍了日志伪造攻击的原理及防护方案。对于需要记录用户输入的场景,ESAPI编码是兼顾安全性和实用性的最佳选择。完整示例代码可在GitHub获取。