繁体   English   中英

Java - 我怎样才能完全清除变量

[英]Java - How can I completely clear a variable

我有一个 Spring 引导应用程序,它使用 CredentialsService class 将凭据存储为 GuardedStrings 并在其他类请求时返回它们。

问题出现的地方在于我们使用 Checkmarx 来扫描我们的代码并发现潜在问题。 在用户名/密码的存储不再是问题的情况下,我仍然必须使用字符串变量来返回纯文本凭据。 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 方法中创建一个单独的线程来将“清除”变量设置为 null,因为我将值返回给请求者。 虽然我可以确认这种最新方法确实为请求者提供了正确的值,并将变量设置为 null,但似乎没有什么能满足 Checkmarx 的要求。

有没有人有任何想法?

提前致谢。

D

一旦将敏感数据放入像String这样的不可变 object 中,数据将在 memory 中保留很长时间。 您可以释放变量,但即使没有物理参考,该值仍将位于 memory 中。 你可以运行 GC,它仍然会存在。 唯一有帮助的是使用相同的 memory 空间创建另一个变量并覆盖该值。

长话短说:只要你把密码放在String中,Checkmarx 就会抱怨。

你有两件事可以做:

  • 您要么仅依赖char[]并在使用后清除数组,
  • 或者如果您被迫为您的案例请求特殊例外,请使用String值。

好吧,通过将密码作为常规String返回/传输,您有点丢掉了在GuardedString中存储密码的所有价值。

对Checkmarx了解不多,但它只是一个扫码工具,所以很容易上当。 我建议实际解决问题,而不是试图将它们扫到地毯下。

  1. 请注意GuardedString构造函数接受char[] ,而不是String 这是第一个问题——你应该将你的密码从源代码作为char[]携带到这一点—— 这里有更多关于它的信息。
  2. 不要将String返回给您的消费者 - 返回GuardedString或至少一个char[]
  3. 取决于您使用此类/库的目标消费者,但尝试为他们提供一种在尽可能短的时间内访问实际密码的方法,并在使用后清除char[] (以消费者不会拥有的方式)自己做,因为他可以忘记)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM