这是一个头脑风暴的问题,关于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!!!");
}
}
可以改进吗?它应该改进吗?是否无法实现在安全级别中锁定秘密的想法?
编辑
关联:
有些人质疑我在这里提出的问题的相关性.虽然我要问一个普遍的问题,以便触发一个开放的对话,但这个课程有一个非常具体的应用:
>如果我想解密某些消息,我需要将私钥数据加载到类中.如果我无法阻止其他Java代码访问它,则无法创建安全系统.当然,如果我想要解密一条消息,我宁愿在课堂上这样做而不是泄露秘密,但是,保险箱必须保持牢不可破.
澄清:
>类的实例仅在运行时创建,而不是在编译时创建
>代码可以在Web服务器应用程序或任何桌面或设备应用程序中运行
>该类仅用于在运行时存储密钥,在内存中,没有计划保留它(对于持久性,可以/应该使用经典加密技术)
事实:
>要在Java应用程序中实现安全性,应该设置一个SecurityManager实例,其中根据需要覆盖检查方法
>此应用程序可以使用安全类加载器加载不受信任的代码,并为其加载的类分配保护域.该域不应包含RuntimePermission(“setSecurityManager”).
>不受信任的代码可以尝试更改SecurityManager,但由于安全类加载器未授予setSecurityManager权限,因此将抛出SecurityException.
解决的问题:
关于执行环境,我们需要区分两种情况:
>受控环境:我们开始使用不受信任的代码尝试打破“安全”的应用程序.
如果我们设置一个适当的SecurityManager禁用反射并限制任何加载的不受信任代码的权限,那么我们的秘密是安全的.
>不受控制的环境:黑客开始使用不受信任的代码试图打破我们的“安全”的应用程序.
黑客可以使用自己的安全管理器和安全类加载器创建自己的应用程序.它可以从类路径加载我们的代码并执行它,就好像它是我们自己的应用程序一样.在这种情况下,他可以打破保险箱.
>正如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来阻止对其进行访问.您需要控制其运行的环境才能工作,例如您限制访问的服务器.
但是,您编辑的问题提到代码可以在任何桌面或设备上运行.在那种情况下,你真的无法做任何事情来保护秘密免受其他可以做任何事情的进程.即使你在内存中加密它,另一个进程也可以直接拦截密钥甚至是明文秘密.
如果您不控制环境,那么您需要一些安全的环境,那么您可能需要考虑不同的方法.也许你可以避免将秘密存储在内存中?