我有一个Spring Boot应用程序,该应用程序使用CredentialsService类将凭据存储为GuardedStrings,并在其他类请求时返回它们。
出现问题的地方是我们使用Checkmarx扫描代码并发现潜在问题。在用户名/密码存储不再是问题的地方,我仍然必须使用String变量来返回纯文本凭据。 Checkmarx不喜欢这样-特别是对于密码。
这是CredentialsService的缩写视图:
@Component
public class CredentialsService {
final ExecutorService executor = Executors.newSingleThreadExecutor();
private GuardedString customerApiPassword;
. . .
private StringBuilder clearCustomerApiPassword;
public CredentialsService( . . .
@Value("${customerapi.pwd}") String customerApiPassword,. . .) {
setCustomerApiPassword(customerApiPassword);
. . .
}
private void setCustomerApiPassword(String customerApiPasswordString) {
this.customerApiPassword = new GuardedString(customerApiPasswordString.toCharArray());
this.customerApiPassword.makeReadOnly();
}
public String getCustomerApiPasswordNo() {
clearCustomerApiPassword = new StringBuilder();
customerApiPassword.access(new GuardedString.Accessor() {
@Override
public void access(final char[] clearChars) {
clearCustomerApiPassword.append(clearChars);
}
});
customerApiPassword.dispose();
System.out.println("DGC: clearCustomerApiPassword is " + clearCustomerApiPassword);
Runnable clearFromMemory = () -> {
clearCustomerApiPassword = null;
System.out.println("DGC: clearCustomerApiPassword is " + clearCustomerApiPassword);
};
executor.execute(clearFromMemory);
return clearCustomerApiPassword.toString();
}
然后请求者通过以下方式访问所需的值:
IntegrationApiUtil.setBasicAuthKey(headers, credentialsService.getCustomerApiUsername(), credentialsService.getCustomerApiPassword());
但是Checkmarx仍然不满意。我使用相同的方法来存储GuardedString用户名和密码,并使用完全相同的方法来清除返回的字符串。 Checkmarx可以使用用户名,但仍然抱怨密码:
Method clearCustomerApiPassword; at line 24 of
src/main/java/com/.../service/CredentialsService.java
defines clearCustomerApiPassword, which is designated to contain user passwords. However, while plaintext
passwords are later assigned to clearCustomerApiPassword, this variable is never cleared from memory.
我已经尝试了各种各样的方法-一种最后一次使用服务后销毁服务的finalize方法,将所有变量显式设置为null并调用垃圾收集器的disposeAll方法。使用上面的代码,我在每个get方法中创建一个单独的线程,以在将值返回给请求者时将“ clear”变量设置为null。虽然我可以确认这种最新方法确实为请求者提供了正确的值,并且也将变量设置为null,但似乎没有什么能让Checkmarx满意。
有人有什么想法吗?
谢谢。
D
答案 0 :(得分:3)
好吧,您通过将密码作为常规GuardedString
进行返回/传输,已经抛弃了在String
中存储密码的所有价值。
对Checkmarx不太了解,但是它只是一个代码扫描工具,因此很容易上当。我建议实际解决这些问题,而不是试图将它们扫在底下。
GuardedString
构造函数接受char[]
,而不是String
。这是第一个问题-您应该将密码从源头一直保存为char[]
-more about it here. String
退还给您的消费者-退回GuardedString
或至少退回char[]
。char[]
(以一种方式该消费者将不必自己做,因为他可以忘记)答案 1 :(得分:1)
一旦您将敏感数据放入String
之类的不可变对象中,该数据将在内存中保留很长时间。您可以释放该变量,但是即使没有物理引用,该值仍将位于内存中。您可以运行GC,它将仍然存在。唯一有帮助的是使用相同的内存空间创建另一个变量并覆盖该值。
长话短说:只要将密码放在String
中,Checkmarx就会抱怨。
您可以做两件事:
char[]
并清除一次使用的数组,String
值。