经常听说字符串是不可变的,这提高了安全性。我理解这样一种观点,即由于字符串是最终的,它们的内容以后不能更改。但即使内容可以更改,我认为它仍然是安全的,因为代码是由开发人员而不是攻击者编写的。或者在实践中,这种攻击实际上是如何进行的?
我在网上看到一个例子,表明如果字符串是可变的,攻击者可以绕过安全性。我不明白。下面的代码是由服务提供商编写的。这是攻击者永远无法触及的部分。无论字符串是否可变,攻击者永远无法修改它们的值,对吧?
public class FileInputStream
{
private String filename;
public FileInputStream(String filename)
{
if (!allowedToReadFile(filename))
throw new SecurityException();
this.filename = filename;
}
...
}
考虑字符串是可变的。在构造函数中,会检查文件名,并将对字符串的引用存储在对象中。可能还有其他方法可以使用该文件名打开文件。如果在调用该方法之前将字符串的内容修改为另一个文件名,则该方法将打开新文件,而不会失败allowedToReadFile
检查,这将在开始时传递具有新内容的字符串时发生。在这种情况下,攻击者可以通过绕过检查并稍后更改字符串的内容来访问几乎任何文件。
一般来说,使数据不可变可以避免许多安全问题和其他问题。如果字符串在Java中是可变的,它不会阻止您从另一个线程更改字符串的内容。您甚至可能会注意到字符串在函数调用过程中发生了变化。将旧字符串的一半和新字符串的一半打印到屏幕上。它甚至可能干扰Unicode编码。另一个问题是,当你改变文字时,文字会发生什么?浪费内存并创建由文字表示的字符串的新实例?或者只为一个文本创建一个字符串。如果字符串是可变的,那么应该有其他系统来复制对象,也许是像C++中那样的系统,其中字符串确实是可变的。指定字符串会复制它们。但这是有代价的:复制或需要一个新的复杂语言功能,该功能允许移动、借用和常量引用传递到函数。JVM不是为这些特性而设计的。