9

我看到另一个帖子的答案:

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

我认为在使用之前检查字符串可以解决问题。为什么将字符串设计为不可变是一个原因?

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

4

3 回答 3

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 + "')");
}

代码会进行一些检查以防止权限升级,但这仅isAlphaNumeric(name)在调用参数时才成立executeStatement

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

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

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


为什么将字符串设计为不可变是一个原因?

这与为什么它在安全方面不好是分开的。

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

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

于 2013-07-24T19:27:30.583 回答
2

这是本书中最古老的安全欺骗:向操作系统提供一些参数,让它验证参数,然后在操作系统引用参数时更新参数,所以它会做与它验证的不同的事情。

这在 60 年代曾用于破坏 IBM OS/360:要请求磁盘 I/O,您将​​向操作系统传递一个包含磁盘地址和内存地址以及其他内容的“通道程序”。操作系统会检查磁盘和内存地址是否是您被授权的位置,然后它将“通道程序”传递给要执行的 I/O 通道硬件,而无需先制作本地副本。确定时间并不难,这样您就可以在检查通道程序之后但在 I/O 通道硬件执行之前修改通道程序,从而允许访问未经授权的磁盘和内存。

(请记住,在这段时间内内存非常宝贵,因此不复制频道程序可以节省大量内存。但是一旦利用它的方法变得相当众所周知,这个漏洞很快就被关闭了。)

(当然,人们必须质疑任何Objective-C 程序是否可以被认为与在同一进程中运行的其他代码相比是“安全的”。Objective-C 的“鸭子类型”本质使得真正的安全性充其量是不可能的。使用不可变字符串更防止意外修改而不是防止恶意修改。)

于 2013-07-24T20:28:49.913 回答
1

您链接到该帖子的更多链接的帖子,其中更详细地解释了该问题:

https://softwareengineering.stackexchange.com/questions/190699/when-and-why-would-we-use-immutable-pointers/190913#190913

于 2013-07-24T19:19:44.980 回答