秘密可以隐藏在提供访问凭证的"安全"java类中吗?

Jér*_*nge 8 java security protection class

这是一个头脑风暴的问题,关于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!!!");
    }

}
Run Code Online (Sandbox Code Playgroud)

可以改进吗?它应该改进吗?是否无法实现在安全级别中锁定秘密的想法?

编辑

关联:

有些人质疑我在这里提出的问题的相关性.虽然我要问一个普遍的问题,以便触发一个开放的对话,但这个课程有一个非常具体的应用:

  • 如果我想解密一些消息,我需要将私钥数据加载到类中.如果我无法阻止其他Java代码访问它,则无法创建安全系统.当然,如果我想要解密一条消息,我宁愿在课堂上这样做而不是泄露秘密,但是,保险箱必须保持牢不可破.

澄清:

  • 该类的实例仅在运行时创建,而不是在编译时创建
  • 代码可以在Web服务器应用程序或任何桌面或设备应用程序中运行
  • 该类仅用于在运行时存储密钥,在内存中,没有计划保留它(对于持久性,可以/应该使用经典加密技术)

事实:

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

解决的问题:

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

  • 受控环境:我们开始使用不受信任的代码试图打破我们的"安全"的应用程序.

如果我们设置一个适当的SecurityManager禁用反射并限制任何加载的不受信任代码的权限,那么我们的秘密是安全的.

  • 不受控制的环境:黑客开始使用不受信任的代码试图打破我们的"安全"的应用程序.

黑客可以使用自己的安全管理器和安全类加载器创建自己的应用程序.它可以从类路径加载我们的代码并执行它,就好像它是我们自己的应用程序一样.在这种情况下,他可以打破保险箱.

  • 正如另一个问题所确定的那样,sun.misc.Unsafe无法打破安全管理器

Whi*_*g34 12

不,它与其他Java代码不安全.您的秘密可以从这样的实例中检索Safe:

Field field = safe.getClass().getDeclaredField("secret");
field.setAccessible(true);
String secret = (String) field.get(safe);
Run Code Online (Sandbox Code Playgroud)

更新:如果您控制要隐藏其他Java代码的加载,则可能使用自定义SecurityManagerClassLoader阻止访问它.您需要控制其运行的环境才能工作,例如您限制访问的服务器.

但是,您编辑的问题提到代码可以在任何桌面或设备上运行.在那种情况下,你真的无法做任何事情来保护秘密免受其他可以做任何事情的进程.即使你在内存中加密它,另一个进程也可以直接拦截密钥甚至是明文秘密.

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


Vla*_*hev 12

这种"安全"是可笑的.

它在哪里运行?在我的桌面上?我用调试器连接到JVM并以明文形式查看所有秘密.

或者我将代码放在旁边并使用反射来转储内容.

或者我通过BCEL注入我自己的代码修改,并修改Safe的构造函数以将"secret"值转储到文件中.

或者我只需将整个包替换为我的同名,将其放入bootstrap类加载器中.

或者我甚至可以修改和编译java源代码以获得修改后的JVM.

或者......我可以列出几种从运行时实例中提取值的方法!

任何安全设计中的真正问题是:谁是攻击者?什么是威胁模型?没有回答这个问题,这个话题毫无意义.

  • 我控制JVM.我可以设置我想要的任何安全策略.我可以预加载我想要的任何类,包括我自己的SecureClassLoader实现.我是JVM上的上帝和沙皇. (8认同)
  • roadto yamburg是对的.要么你信任客户,要么你不必担心被盗的秘密,或者你不信任他,然后他就可以做任何事情来破解它.如果您不信任客户,您应该将秘密保存在您自己或某些可靠的层级. (3认同)
  • @Peter Lawrey:根据Ed Felten等人的研究,在工作温度下几分钟到几分钟,如果冷却几十分钟:http://freedom-to-tinker.com/blog/felten/new-research-result-cold -boot攻击磁盘加密 (2认同)