【问题标题】:Is it secure to save sensitive data in private static fields in Java?在 Java 的私有静态字段中保存敏感数据是否安全?
【发布时间】:2019-12-04 21:52:49
【问题描述】:

我最近偶然发现了一些无法按照我习惯的方式传递数据的问题。

假设我们创建了一个提供者类,它被另一个我们无法修改的消费者类实例化和调用。提供者为消费者提供了一些需要敏感数据的对象实例。显然,将这​​些数据硬编码到我们的提供程序类中是一种不好的做法。在我的例子中,这些敏感数据是在运行时生成的,不能硬编码。

我的想法是为该提供程序类提供一个私有静态字段,该字段的设置器,而不是获取器。现在,即使创建了该提供程序类的实例,我们也无法访问该私有静态字段,只有提供程序类本身可以读取它。


让我们提供一些代码。假设我们有以下 Consumer 类和 Provider 接口:

消费者

public class Consumer {

    private final Class<? extends ProviderInterface> clazz;

    public Consumer(Class<? extends ProviderInterface> clazz) {
        this.clazz = clazz;
    }

    public void providerToSystemOut() throws IllegalAccessException, InstantiationException {
        System.out.println(clazz.newInstance().call().toString());
    }

}

提供者接口

public interface ProviderInterface {

    public Object call();

}

消费者只接受消费者的类作为参数。所以我们不能自己创建那个类来提供敏感数据。

为了传递我们的敏感数据,我们创建了以下提供程序和主程序:

提供者

public class Provider implements ProviderInterface {

    private static Object data = null;

    public static void setData(Object data) {
        Provider.data = data;
    }

    public Object call() {
        String str;
        if (data != null && (str = data.toString()).length() > 3) {
            Object object = "successfully received/processed sensitive data: "
                    + str.substring(0, 3)
                    + str.substring(3).replaceAll(".", "*");
            data = null;
            return object;
        } else {
            data = null;
            return "not enough data provided";
        }
    }
}

主要

public class Main {

    public static void main(String[] args) {

        Provider.setData("sensitive data");

        try {
            new Consumer(Provider.class).providerToSystemOut();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}

我的问题

这段代码工作得很好,而且看起来很安全。但我想确定这是否是解决这个问题的最佳方法。我使用的方法是一种好的做法吗?它安全吗?是否有一些简单的方法可以让某人获取敏感数据?如果这可能不是最好的方法,那该怎么做更好?

一些背景

我在处理硒化物时遇到了这个问题。通常 selenide 会自己创建其 WebDriver 实例。要为其提供自定义 WebDriver,需要一个 Provider 类。 Selenide 具有该提供程序的类名的系统属性,并使用此字符串创建自定义提供程序的实例并调用为 selenide 提供 WebDriver 的方法。

【问题讨论】:

  • 在这种情况下,您所说的“安全”是什么意思?一个JVM还是多个?所有值都未加密地驻留在内存中。
  • 可能是对here问题的部分贡献
  • 如果“敏感数据”存储在代码中,则可以提取。您需要提供某种编码以确保难以解码或进行逆向工程

标签: java security static field private


【解决方案1】:

从静态字段访问数据实际上更容易通过反射获得,但实际上它是静态的还是私有的并不重要。

但是,您只需要担心您存储的数据是否可供客户使用...

即)无论出于何种原因,您都在将您的 jar 文件分发给其他人/客户。

如果是这种情况,那么就没有真正的方法可以阻止某人访问数据。

如果您有权访问 jar 文件,则可以执行以下操作,对代码执行任何您想做的事情。

public static void agentmain(String agentArgs, Instrumentation inst) {
    Class[] allYourClassesAtRuntime = inst.getAllLoadedClasses();
    for (Class yourClass : allYourClassesAtRuntime) {
        try {
            if (yourClass.getSimpleName().equals("Provider")) {
                Field yourClassField = yourClass.getField("data");
                yourClassField.setAccessible(true); //destroys private
                Object yourData = yourClassField.get(null);
                System.out.println("Got your data: " + yourData);
                //can do as you wish from here
            }
        } catch (NoSuchFieldException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

当代理连接到JVM时调用上述方法。

TL/DR:您的客户端数据永远不会安全,因此您应该将所有希望保护的东西都保存在服务器端,并在两者之间进行协商。 如果在某些情况下您必须在客户端拥有一些敏感数据,那么不要在构造函数或方法之外保留任何您不想窥探的对象。把它们放在本地。构造函数也比方法更难反编译。

【讨论】:

  • 有两种方法可以防止对私有字段的反射访问:在 Java 9 或更高版本中将程序构建为模块,或者安装SecurityManager
猜你喜欢
  • 1970-01-01
  • 2014-08-20
  • 2017-09-15
  • 2010-09-29
  • 2017-10-29
  • 2020-10-27
  • 1970-01-01
  • 1970-01-01
  • 2013-01-24
相关资源
最近更新 更多