为什么可变字符串会导致安全问题?

Rya*_*yan 9 java string immutability

我从另一篇文章中看到了答案:

String已广泛用作许多java类的参数,例如用于打开网络连接,打开数据库连接,打开文件.如果String不是不可变的,这将导致严重的安全威胁.

我认为在使用之前检查字符串可以解决问题.为什么字符串被设计为不可变的原因?

谁能给我一个具体的代码示例?

Mik*_*uel 5

通常,在值不变时编写和审查敏感代码会更容易,因为可能影响结果的操作交错较少。

想象一下代码

void doSomethingImportant(String name) {
  if (!isAlphaNumeric(name)) { throw new IllegalArgumentException(); }
  Object o = lookupThingy(name);
  // No chance of SQL-Injection because name is alpha-numeric.
  connection.executeStatement("INSERT INTO MyTable (column) VALUES ('" + name + "')");
}
Run Code Online (Sandbox Code Playgroud)

代码做了一些检查以防止权限升级,但这仅isAlphaNumeric(name)在调用 to 参数时为真executeStatement

如果前两个语句被重新排序,那么这不会是一个问题,所以不安全性部分是由错误的交错引起的。但是其他代码可能会调用此函数并假定它name没有更改,因此可能必须执行并重新执行有效性检查。

如果String不是不可变的,那么它可能已被lookupThingy. 为确保安全检查有效,必须正确执行大量代码才能使此代码免受 SQL 注入的影响。

不仅必须正确执行的代码量更大,而且对一个功能进行本地更改的维护者可能会影响其他功能的安全性。非局部效应使代码维护变得困难。维护安全属性总是很冒险的,因为安全漏洞很少很明显,因此随着时间的推移,可变性会导致安全性下降。


为什么字符串被设计为不可变的原因?

这与为什么它在安全方面很糟糕是分开的。

人们普遍认为,用具有现成的不可变字符串类型的语言编写的程序比没有的程序执行的不必要的缓冲区副本更少。不必要的缓冲区副本会占用内存,导致 GC 流失,并可能导致对大输入的简单操作比对小输入执行更差。

人们还普遍认为,使用不可变字符串时更容易编写正确的程序,因为您不太可能无法防御性地复制缓冲区。

  • 或者更糟的是,也许字符串对另一个线程是可见的,然后它可以在完整性检查和使用之间改变它的值——即使没有明确的干预调用! (4认同)