Heap inspection漏洞疑问:如何用char[]适配需String的密码传参?
问题
我需要将密码传入某个调用方法中。当我使用以下代码时:
byte[] dataSourcePasswdDecoded = Base64.getDecoder().decode(dataSourcePasswdEncoded); String dataSourcePasswd = new String(dataSourcePasswdDecoded); hikariDataSource.setPassword(dataSourcePasswd);
该代码经Fortify扫描后,被报告存在Heap inspection漏洞,原因是将密码赋值给了String类型变量。
但Fortify并未对原始代码提出异议:
hikariDataSource.setPassword(env.getProperty("spring.datasource.password"));
尽管env.getProperty()同样返回String类型。
Fortify给出的推荐写法是:
private JPasswordField pf; ... final char[] password = pf.getPassword(); // use the password ... // erase when finished Arrays.fill(password, ' ');
但当目标方法要求传入String类型密码时,该如何使用char[]类型的密码呢?
解决方案
1. 先搞懂Fortify的检测逻辑差在哪
Fortify不对env.getProperty()报漏洞,是因为它把框架返回的字符串认定为可信来源,默认这类字符串不会在内存中留下可控的明文痕迹;而你手动解码后生成的String,是自己主动在堆上创建的明文对象,String又是不可变的,一旦创建就没法主动清除内存里的内容,只能等GC回收,这才触发了Heap inspection告警。
2. 目标方法只能传String时的处理
如果目标方法(比如setPassword(String))只接受String类型,可以临时创建String,用完立刻让它失去引用,同时尽量缩短它的生命周期:
byte[] dataSourcePasswdDecoded = Base64.getDecoder().decode(dataSourcePasswdEncoded); // 直接在方法调用里创建临时String,不赋值给变量延长存活时间 hikariDataSource.setPassword(new String(dataSourcePasswdDecoded)); // 立即清除byte数组里的敏感内容 Arrays.fill(dataSourcePasswdDecoded, (byte) 0);
这么做的好处是:临时String没被存到持久变量里,会更快被GC标记;同时主动清空了保存明文的byte数组,最大程度降低内存残留敏感数据的风险。
3. 更彻底的优化方向
如果项目允许,优先用框架原生的密码注入方式(比如直接调用env.getProperty()),避免手动解码处理密码,从源头减少敏感数据暴露的可能。
如果必须手动处理密码,想完全规避String的不可变问题,可以:
- 检查目标库有没有支持char[]参数的重载方法(比如HikariCP的
setPassword其实有setPassword(char[] password)重载,直接传char[]就行) - 要是没有重载方法,只能临时转String,但一定要在使用后立刻清除原char[]/byte[]的内容,而且别把这个String存到任何变量里。
内容的提问来源于stack exchange,提问作者techie11
相关产品推荐
相关产品推荐

