我刚刚了解到 aString
是不可变的。当我阅读它背后的原因时,出现了一些原因,例如性能提高,或者由于它的值不能被修改,它可以被多个线程共享。这些原因我都明白。
但我不明白它与安全性有何关系。String
不可变对 Java 安全性有何帮助?
A very common practice in writing class libraries is storing the parameters passed into your API, say, in a constructor, like this:
public class MyApi {
final String myUrl;
public MyApi(String urlString) {
// Verify that urlString points to an approved server
if (!checkApprovedUrl(urlString)) throw new IllegalArgumentException();
myUrl = urlString;
}
}
Were String
mutable, this would lead to a subtle exploit: an attacker would pass a good URL, wait for a few microseconds, and then set the URL to point to an attack site.
Since storing without copying is a reasonably common practice, and because strings are among the most commonly used data types, leaving strings mutable would open up many APIs that are not written yet open to a serious security problem. Making strings immutable closes this particular security hole for all APIs, including the ones that are not written yet.
SecurityManager 概念需要不可变的字符串才能工作。dasbklinkenlight 的答案已经走在正确的轨道上,但可变字符串将完全打破沙盒概念。
例如,当您new FileInputStream("foo");
读取文件时,API 实现将在内部执行以下操作:
如果调用者能够在这两个步骤之间修改字符串,则一个文件的安全检查可能会成功,而实际上将打开另一个文件。
字符串是不可变的意味着你不能改变对象本身,但你当然可以改变引用。当您调用(例如)a = "ty" 时,实际上是在将 a 的引用更改为由字符串文字 "ty" 创建的新对象。改变一个对象意味着使用它的方法来改变它的一个字段,例如:
Foo x = new Foo("the field");
x.setField("a new field");
System.out.println(x.getField()); // prints "a new field"
在不可变类(声明为 final)中,例如 String,您不能更改当前 String,但可以返回一个新 String,即:
String s = "some text";
s.substring(0,4);
System.out.println(s); // still printing "some text"
String a = s.substring(0,4);
System.out.println(a); // prints "some"