这是一个关于 Java 的可能性(或不可能性)的头脑 Storm 问题。我想知道是否有可能在一个类中隐藏一个 secret 并防止再访问它仅使用 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!!!");
}
}
可以改进吗?应该改进吗?将 secret 锁定在安全类中的想法是不可能实现的吗?
编辑
相关性:
有些人质疑我在这里提出的问题的相关性。尽管我问的是一个一般性问题以引发公开对话,但此类有一个非常具体的应用:
- 如果我想解密一些消息,我需要将私钥数据加载到一个类中。如果我不能阻止其他 Java 代码访问它,那么就不可能创建一个安全的系统。当然,如果我想解密一条消息,我宁愿在类里面解密也不愿泄露 secret ,但是,保险箱必须保持牢不可破。
澄清:
- 类的实例只在运行时创建,不在编译时
- 代码可以在网络服务器应用程序或任何桌面或设备应用程序中运行
- 该类仅用于在运行时在内存中存储 secret ,不打算持久化它(为了持久化,可以/应该使用经典加密技术)
事实:
- 要在 Java 应用程序中实现安全性,应该设置一个 SecurityManager 实例,其中检查方法根据需要被覆盖
- 此应用程序可以使用安全类加载器加载不受信任的代码,并为其加载的类分配一个保护域。此域不应包含 RuntimePermission("setSecurityManager")。
- 不受信任的代码可以尝试更改 SecurityManager,但由于安全类加载器未授予 setSecurityManager 权限,因此将抛出 SecurityException。
已解决的问题:
关于执行环境,我们需要区分两种情况:
- 受控环境:我们开始启动应用程序,该应用程序将使用不受信任的代码来试图破坏我们的“安全”。
如果我们设置适当的 SecurityManager 来禁用反射并限制任何加载的不受信任代码的权限,那么我们的 secret 就是安全的。
- 不受控制的环境:黑客开始启动使用不受信任代码的应用程序,试图破坏我们的“安全”。
黑客可以使用自己的安全管理器和安全类加载器创建自己的应用程序。它可以从类路径加载我们的代码并执行它,就好像它是我们自己的应用程序一样。在这种情况下,他可能会破坏保险箱。
- 成立于 a separate question , sun.misc.Unsafe 不能破坏安全管理器
最佳答案
不,它不受其他 Java 代码的影响。您的 secret 可以从 Safe
的实例中检索,如下所示:
Field field = safe.getClass().getDeclaredField("secret");
field.setAccessible(true);
String secret = (String) field.get(safe);
更新:如果您控制要隐藏 secret 的其他 Java 代码的加载,您可以使用自定义 SecurityManager
或 ClassLoader
以防止访问它。你需要控制它运行的环境才能工作,例如您限制访问的服务器。
然而,您编辑的问题提到代码可以在任何桌面或设备上运行。在那种情况下,您实际上无法采取任何措施来保护 secret 不受其他几乎可以做任何事情的进程的影响。即使您在内存中对其进行加密,另一个进程也可以在其传递时拦截 key 甚至明文 secret 。
如果您无法控制需要确保安全的环境,那么您可能需要考虑采用不同的方法。也许您可以完全避免将 secret 存储在内存中?
关于java - secret 可以隐藏在提供访问凭证的 'safe' java 类中吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5761519/