秘密能藏在';安全';提供访问凭据的java类?

秘密能藏在';安全';提供访问凭据的java类?,java,security,class,protection,Java,Security,Class,Protection,这是一个集思广益的问题,关于在Java中什么是可能的(或者不是)。我想知道是否有可能在一个类中隐藏一个秘密,并且仅使用Java代码或其任何功能阻止访问它(安全性、反射、序列化、类加载器,你可以说……) 以下是我到目前为止的想法: public final class Safe { private String secret; private HashMap<String, Credentials> validCertificates = ne

这是一个集思广益的问题,关于在Java中什么是可能的(或者不是)。我想知道是否有可能在一个类中隐藏一个秘密,并且仅使用Java代码或其任何功能阻止访问它(安全性、反射、序列化、类加载器,你可以说……)

以下是我到目前为止的想法:

public final class Safe {

    private String secret;
    private HashMap<String, Credentials> validCertificates
            = new HashMap<String, Credentials>();

    public Safe(String aSecret) {
        this.secret = aSecret;
    }

    public final class Credentials {
        private String user;
        private Credentials(String user) {
            this.user = user;
        }
    }

    public final Credentials getCredential(String user) {
        // Following test is just for illustrating the intention...
        if ( "accepted".equals(user) ) {
            return new Credentials(user);
        } else {
            return null;
        }
    }

    public String gimmeTheSecret(Credentials cred) {
        if ( this.validCertificates.get(cred.user) == cred ) {
            return secret;
        } else {
            return null;
        }
    }

    private void writeObject(ObjectOutputStream stream) throws IOException {
        throw new RuntimeException("No no no no no no no!!!");
    }

}
公共最终安全等级{
私人字符串秘密;
私有哈希映射有效证书
=新HashMap();
公共保险箱(字符串aSecret){
这个秘密=一个秘密;
}
公开期末课程证书{
私有字符串用户;
私有凭据(字符串用户){
this.user=用户;
}
}
公共最终凭据getCredential(字符串用户){
//下面的测试只是为了说明意图。。。
如果(“接受”。等于(用户)){
返回新凭据(用户);
}否则{
返回null;
}
}
公共字符串gimmethecret(凭据cred){
if(this.validCertificates.get(cred.user)==cred){
归还秘密;
}否则{
返回null;
}
}
私有void writeObject(ObjectOutputStream流)引发IOException{
抛出新的RuntimeException(“No!!!”);
}
}
可以改进吗?应该改进吗?将秘密锁定在安全类中的想法是不可能实现的吗

编辑

相关性:

有些人质疑我在这里提出的问题的相关性。虽然我问的是一个一般性的问题,以引发一场公开的对话,但这门课有一个非常具体的应用:

  • 如果我想解密一些消息,我需要将私钥数据加载到类中。如果我不能阻止其他Java代码访问它,那么就不可能创建一个安全的系统。当然,如果我想解密一条信息,我宁愿在课堂上解密,也不愿泄露秘密,但保险箱还是要牢不可破
澄清:

  • 类的实例仅在运行时创建,而不是在编译时创建
  • 代码可以在web服务器应用程序或任何桌面或设备应用程序中运行
  • 该类仅用于在运行时将秘密存储在内存中,不打算将其持久化(对于持久化,可以/应该使用经典的加密技术)
事实:

  • 为了在Java应用程序中实现安全性,应该设置一个SecurityManager实例,在该实例中检查方法会根据需要被覆盖
  • 此应用程序可以使用安全类加载器加载不受信任的代码,并为其加载的类分配保护域。此域不应包含运行时权限(“setSecurityManager”)
  • 不受信任的代码可以尝试更改SecurityManager,但由于安全类加载程序未授予setSecurityManager权限,因此将抛出SecurityException
已解决的问题:

关于执行环境,我们需要区分两种情况:

  • 受控环境:我们可以启动应用程序,该应用程序将使用不受信任的代码试图破坏我们的“安全”
如果我们设置了适当的SecurityManager来禁用反射并限制对任何加载的不受信任代码的权限,那么我们的秘密是安全的

  • 不受控制的环境:黑客启动应用程序,该应用程序使用不受信任的代码试图破坏我们的“安全”
黑客可以使用自己的安全管理器和安全类加载器创建自己的应用程序。它可以从类路径加载我们的代码,并像执行我们自己的应用程序一样执行它。在这种情况下,他可能会打破保险箱

  • 如中所述,sun.misc.Unsafe不能破坏安全管理器

不,不能以这种方式在类中嵌入秘密。如果您编译了它,那么我就可以在生成的类文件上运行
strings
,它可能就在那里


如果您只是尝试验证它,那么您可以通过在其中存储散列来执行此操作。一旦您想要验证输入,对其进行散列并比较散列。

否,您不能以这种方式在类中嵌入秘密。如果您编译了它,那么我就可以在生成的类文件上运行
strings
,它可能就在那里


如果您只是尝试验证它,那么您可以通过在其中存储散列来执行此操作。一旦您想要验证输入,就对其进行散列并比较散列。

不,它对其他Java代码不安全。您的秘密可以从
Safe
的实例中检索,如下所示:

Field field = safe.getClass().getDeclaredField("secret");
field.setAccessible(true);
String secret = (String) field.get(safe);
更新:如果您控制要隐藏秘密的其他Java代码的加载,您可能可以使用自定义
SecurityManager
ClassLoader
来阻止对它的访问。不过,您需要控制运行此功能的环境,例如,限制访问的服务器

但是,您编辑的问题提到代码可以在任何桌面或设备上运行。在这种情况下,您实际上无法保护机密,使其不受其他进程的影响,而这些进程几乎可以做任何事情。即使在内存中对其进行加密,另一个进程也可以在密钥传递时截取密钥,甚至截取明文密钥


如果你不控制环境,你需要一些安全的东西,那么你可能需要考虑一种不同的方法。也许您可以完全避免将秘密存储在内存中?

不,它对其他Java代码不安全。您的秘密可以从
Safe
的实例中检索,如下所示:

Field field = safe.getClass().getDeclaredField("secret");
field.setAccessible(true);
String secret = (String) field.get(safe);
更新:如果控制要隐藏秘密的其他Java代码的加载,则可能可以使用自定义
SecurityManager