我看到了另一个post的答案:
String已广泛用作许多java类的参数,例如用于打开网络连接,用于打开数据库连接,打开文件。如果String不是不可变的,这将导致严重的安全威胁。
我认为在使用之前检查字符串可以解决问题。为什么字符串被设计为不可变的原因?
有人能给我一个具体的代码示例吗?
答案 0 :(得分:4)
通常,当值不变时,编写和查看敏感代码会更容易,因为 可能影响结果的操作交错较少。
想象一下像
这样的代码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流失,并且可能导致大输入上的简单操作比小输入更糟糕。
人们普遍认为,在使用不可变字符串时编写正确的程序更容易,因为你不太可能无法防御地复制缓冲区。
答案 1 :(得分:2)
这是本书中最古老的安全恶搞:向操作系统提供一些parm,让它验证parm,然后在操作系统引用parm时更新parm,这样它将执行与验证的不同的东西。
这用于在60年代打破IBM OS / 360:要请求磁盘I / O,您将通过操作系统“通道程序”,其中包含磁盘地址和内存地址以及其他内容。操作系统会检查磁盘和内存地址是否是您获得授权的位置,然后它会将“通道程序”传递给要执行的I / O通道硬件,而不首先进行本地复制。在检查通道程序之后但在I / O通道硬件执行之前修改通道程序并不困难,允许访问未经授权的磁盘和内存。
(请记住,在这段时间内,内存非常宝贵,所以不要复制频道程序会节省大量的内存。但是一旦利用它的方式变得众所周知,这个漏洞就会很快被关闭。)
(当然,必须质疑任何 Objective-C程序是否可以被认为是在同一进程中运行的其他代码“安全”。目标-C的“鸭子打字”性质是真的安全性最好不可能。使用不可变字符串更能防止意外修改,而不是恶意修改。)
答案 2 :(得分:1)