【缺陷周话】第50期:日志伪造
字数 1275 2025-08-18 11:38:53

日志伪造漏洞分析与防御指南

1. 漏洞定义

日志伪造(Log Forging)是指当日志条目包含未经过授权的用户输入时,攻击者可以通过向应用程序提供包含特殊字符的内容,在日志文件中插入错误的条目。根据CWE ID 117定义,这属于"日志输出中和不当"(Improper Output Neutralization for Logs)的安全缺陷。

2. 漏洞危害

  • 日志格式破坏:恶意条目会破坏日志文件格式
  • 攻击轨迹掩盖:可以掩盖攻击者的入侵轨迹
  • 信任边界跨越:可能跨越信任边界获取敏感数据
  • XSS攻击:注入的脚本可能在使用Web浏览器查看日志时执行
  • 权限提升:通过获取管理员Cookie副本获得管理员访问权限

3. 漏洞原理

攻击者利用回车符(%0a)和换行符(%0d)等特殊字符构造输入,将合法的日志条目进行拆分,从而:

  1. 在日志中插入伪造条目
  2. 将单一日志条目拆分为多个看似合法的条目

示例攻击

当用户输入:

jack%0a%0aINFO:+User+login+succeeded+for+tom

日志记录会变为:

INFO: User login failed for jack
INFO: User login succeeded for tom

4. 漏洞代码示例

缺陷代码

protected void doGet(HttpServletRequest request, HttpServletResponse response) 
    throws ServletException, IOException {
    super.doGet(request, response);
    String username = request.getParameter("username");
    String password = request.getParameter("password");
    
    if(isValidUser(username, password)) {
        logger.info("User login succeeded for " + username);
    } else {
        logger.info("User login failed for " + username);
    }
}

问题分析

  1. 直接拼接用户输入(username)到日志语句
  2. 未对用户输入进行任何过滤或转义
  3. 允许特殊字符(如换行符)进入日志系统

5. 修复方案

修复代码示例

protected void doGet(HttpServletRequest request, HttpServletResponse response) 
    throws ServletException, IOException {
    super.doGet(request, response);
    String username = request.getParameter("username");
    String password = request.getParameter("password");
    
    if(isValidUser(username, password)) {
        logger.info("User login succeeded for " + StringEscapeUtils.escapeJavaScript(username));
    } else {
        logger.info("User login failed for " + StringEscapeUtils.escapeJavaScript(username));
    }
}

修复要点

  1. 使用StringEscapeUtils.escapeJavaScript()对用户输入进行转义
  2. 转义处理会处理特殊字符,防止日志条目拆分
  3. 使用Apache Commons Lang库提供的工具类

6. 防御措施

输入控制

  1. 输入验证:假设所有输入都是恶意的
  2. 严格规范:拒绝任何不严格符合规范的输入
  3. 字段属性校验
    • 长度限制
    • 输入类型检查
    • 值范围验证
  4. 数据转换:将输入转换为符合规格的格式

输出控制

  1. 编码指定:明确指定日志输出的编码格式
  2. 特殊字符处理
    • 转义换行符(\n)、回车符(\r)
    • 转义其他控制字符
  3. 日志框架配置:使用安全配置的日志框架

推荐技术

  1. Java
    • StringEscapeUtils.escapeJavaScript() (Apache Commons Lang)
    • ESAPI.encoder().encodeForHTML() (OWASP ESAPI)
  2. 其他语言:使用相应语言的HTML/日志转义函数

7. 检测方法

  1. 静态分析:使用代码安全检测工具(如奇安信代码卫士)
  2. 动态测试:尝试输入包含特殊字符的测试用例
  3. 日志审计:检查日志中是否存在异常格式的条目

8. 最佳实践

  1. 最小化日志记录:只记录必要的、非敏感信息
  2. 敏感数据过滤:避免在日志中记录密码、令牌等敏感信息
  3. 日志格式标准化:使用结构化日志格式(如JSON)
  4. 日志监控:实施实时日志监控和异常检测
  5. 权限控制:限制日志文件的访问权限

9. 相关标准

  1. CWE:CWE-117 Improper Output Neutralization for Logs
  2. OWASP
    • OWASP Top 10 A1: Injection
    • OWASP Logging Cheat Sheet
日志伪造漏洞分析与防御指南 1. 漏洞定义 日志伪造(Log Forging)是指当日志条目包含未经过授权的用户输入时,攻击者可以通过向应用程序提供包含特殊字符的内容,在日志文件中插入错误的条目。根据CWE ID 117定义,这属于"日志输出中和不当"(Improper Output Neutralization for Logs)的安全缺陷。 2. 漏洞危害 日志格式破坏 :恶意条目会破坏日志文件格式 攻击轨迹掩盖 :可以掩盖攻击者的入侵轨迹 信任边界跨越 :可能跨越信任边界获取敏感数据 XSS攻击 :注入的脚本可能在使用Web浏览器查看日志时执行 权限提升 :通过获取管理员Cookie副本获得管理员访问权限 3. 漏洞原理 攻击者利用回车符( %0a )和换行符( %0d )等特殊字符构造输入,将合法的日志条目进行拆分,从而: 在日志中插入伪造条目 将单一日志条目拆分为多个看似合法的条目 示例攻击 当用户输入: 日志记录会变为: 4. 漏洞代码示例 缺陷代码 问题分析 直接拼接用户输入( username )到日志语句 未对用户输入进行任何过滤或转义 允许特殊字符(如换行符)进入日志系统 5. 修复方案 修复代码示例 修复要点 使用 StringEscapeUtils.escapeJavaScript() 对用户输入进行转义 转义处理会处理特殊字符,防止日志条目拆分 使用Apache Commons Lang库提供的工具类 6. 防御措施 输入控制 输入验证 :假设所有输入都是恶意的 严格规范 :拒绝任何不严格符合规范的输入 字段属性校验 : 长度限制 输入类型检查 值范围验证 数据转换 :将输入转换为符合规格的格式 输出控制 编码指定 :明确指定日志输出的编码格式 特殊字符处理 : 转义换行符( \n )、回车符( \r ) 转义其他控制字符 日志框架配置 :使用安全配置的日志框架 推荐技术 Java : StringEscapeUtils.escapeJavaScript() (Apache Commons Lang) ESAPI.encoder().encodeForHTML() (OWASP ESAPI) 其他语言 :使用相应语言的HTML/日志转义函数 7. 检测方法 静态分析 :使用代码安全检测工具(如奇安信代码卫士) 动态测试 :尝试输入包含特殊字符的测试用例 日志审计 :检查日志中是否存在异常格式的条目 8. 最佳实践 最小化日志记录 :只记录必要的、非敏感信息 敏感数据过滤 :避免在日志中记录密码、令牌等敏感信息 日志格式标准化 :使用结构化日志格式(如JSON) 日志监控 :实施实时日志监控和异常检测 权限控制 :限制日志文件的访问权限 9. 相关标准 CWE :CWE-117 Improper Output Neutralization for Logs OWASP : OWASP Top 10 A1: Injection OWASP Logging Cheat Sheet