使字符串真正不可变

4
我有一个问题,但要得到答案,必须首先接受以下“事实”:在某些情况下,Java字符串可以被修改。这在Artima的文章中已经得到了证明,标题为:“hi there”.equals("cheers !") == true。链接:http://www.artima.com/weblogs/viewpost.jsp?thread=4864。它仍然可以在Java 1.6中良好地工作,并且它肯定与流行的信念相抵触,即“Java字符串始终是不可变的”。所以我的问题很简单:像这样总是可以修改字符串吗?是否有任何JVM安全设置可以打开以防止这种情况发生?

据我理解(但我可能会错),这是通过使用反射访问底层的*char[]数组完成的,由于在Java中无法使数组内容不可变,因此这种方法确实有效。那么有什么办法可以防止访问该char[]*吗? - SyntaxT3rr0r
1
我想你可以随时关闭“Hacking Java Internals”开关,一切都会没问题的。 - Perception
5
所以你试图防止DailyWTF场景的发生。好吧,祝你好运。我认为语言设计者无法为这种情况提供傻瓜式的设计。 - Vineet Reynolds
1
总是有一种选择,可以深入本地代码并开始修改随机内存位置... - pap
2
@pap 没有。如果您需要接受来自不可靠来源的代码(某些系统必须这样做),则应该能够将它们隔离在虚拟机中。实际上这是可能的。 - biziclop
显示剩余2条评论
2个回答

7
你需要添加一个SecurityManager。这个网站提供了一个示例和解释:
运行命令:
java -Djava.security.manager UseReflection

代码如下:

import java.lang.reflect.Field;
import java.security.Permission;

public class UseReflection {
    static{
        try {
            System.setSecurityManager(new MySecurityManager());
        } catch (SecurityException se) {
            System.out.println("SecurityManager already set!");
        }

    }
    public static void main(String args[]) {
        Object prey = new Prey();
        try {
            Field pf = prey.getClass().getDeclaredField("privateString");
            pf.setAccessible(true);
            pf.set(prey, "Aminur test");
            System.out.println(pf.get(prey));
        } catch (Exception e) {
            System.err.println("Caught exception " + e.toString());
        }

    }
}

class Prey {
    private String privateString = "privateValue";
}

class MySecurityManager extends SecurityManager {
     public void checkPermission(Permission perm) {
         if(perm.getName().equals("suppressAccessChecks")){
             throw new SecurityException("Can not change the permission dude.!");
         }

     }
}

2
说了这么多,有相当多的库可能依赖于这种行为,例如Wicket的PropertyModel。 - biziclop
@Vineet Reynolds 希望你不是在设计云服务器。 :) - biziclop
@Vineet Reynolds,我的意思不是个人攻击,只是一个小玩笑,因为你评论中提到的“只是为了防止一些流氓代码运行”的部分引发了这种感觉。在大多数情况下,这种风险是微不足道的,但在某些专业领域,它非常重要。无论如何,你所说的很有趣:为什么关闭封装中的漏洞会成为安全剧院呢? - biziclop
@biziclop,如果假设在云解决方案中使用单个JVM来运行多个应用程序,并且恶意应用程序可以通过反射修改其他应用程序的方法调用结果,那么这将是一种安全剧场。如果真的非常关注云安全,那么每个应用程序一个JVM/进程的解决方案会更加合适。 - Vineet Reynolds
我明白你的意思。但即使使用单独的虚拟机,您也可能希望避免应用程序服务器类被篡改。 - biziclop
显示剩余2条评论

5
所有反射操作都要经过您安装的SecurityManager进行检查。
如果您担心恶意代码,那么无论如何都必须有一个SecurityManager。如果没有,那就不必费心了。如果有人非常想自毁长城,那就让他们去吧。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接