Java异常日志如何避免泄露敏感信息且不丢失堆栈关键内容
问题描述
Java堆栈跟踪信息可能包含敏感信息(本示例中为数据库密码),如果完整堆栈被日志框架(此处为Java Util Logging)记录,就会造成敏感信息泄露风险。我们需要在不丢失堆栈其他关键定位信息的前提下,避免敏感内容被写入日志文件。
问题复现示例
业务代码
package javalogspassword; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; import java.util.logging.Level; import java.util.logging.Logger; public class JavaLogsPassword { private static final Logger LOG = Logger.getLogger(JavaLogsPassword.class.getName()); public static void main(String[] args) { Connection conn; try { conn = DriverManager.getConnection("jdbc:mysql://localhost/test?" + "user=root&password="); LOG.log(Level.FINER, "Connected"); try (Statement statement = conn.createStatement()) { // 该语句存在语法错误 statement.execute("ALTER USER test IDENT BY '*Choose-a-good-password*'"); } conn.close(); } catch (SQLException ex) { // 密码 '*Choose-a-good-password*' 会被写入日志 LOG.throwing(JavaLogsPassword.class.getName(), "main", ex); } } }
日志配置(logging.properties)
handlers= java.util.logging.FileHandler .level= INFO java.util.logging.FileHandler.pattern = java%u.log javalogspassword.level = FINER
启动命令
java -Djava.util.logging.config.file=logging.properties -jar dist/JavaLogsPassword.jar
运行后生成的java0.log文件中会包含上述明文密码。
可行解决方案
- 业务层规避:涉及密码、密钥等敏感数据的操作,优先使用预编译语句传参,不要将明文敏感信息直接拼接到SQL、异常提示等可能被打印到日志的内容中,从根源上避免敏感内容进入异常信息。
- 异常信息脱敏:捕获异常后,对原始异常的message内容做正则匹配替换,将符合敏感特征的内容(比如
IDENTIFIED BY '.*?'、password=.*?(&|$)这类规则)替换为***,再将处理后的异常交给日志框架打印。 - 日志框架层全局处理:自定义Java Util Logging的
Formatter实现类,在日志内容最终输出前做全局脱敏扫描,统一替换所有日志中的敏感信息。该方案无需修改业务代码,仅需在logging.properties中指定自定义的格式化器即可,侵入性最低。
内容的提问来源于stack exchange,提问作者Ari
相关产品推荐
相关产品推荐

