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