Java'final'关键字是否真正提高了安全性?

时间:2010-01-21 18:34:48

标签: java security final

虽然有many reasons to use the 'final' keyword in Java,但我一遍又一遍地听到的一个问题是它使您的代码更安全。虽然这似乎在这个微不足道的案例中有意义:

public class Password
{
    public final String passwordHash;
    ...
}

使用final关键字,您可以预期没有恶意代码可以更改变量passwordHash。但是,using reflection可以更改passwordHash字段的最终修饰符。

'final'提供任何真正的安全性,还是只是安慰剂?

修改 有一些非常有趣的讨论,我希望我能接受不止一个答案。感谢大家的意见。

12 个答案:

答案 0 :(得分:37)

在'经受住攻击'的意义上,这不是'安全';它更像是“更难搞乱”。

我更喜欢“安全”这个词;我觉得它更像是防止意外,而不是恶意。

答案 1 :(得分:10)

Java的final关键字不用于此类安全性。它不能代替通常需要加密解决方案。

在这类讨论中,“安全”的含义通常是安全对象模型的概念 - 也就是说,对象模型不能被消费者操纵,以达到该类原作者无意的目的。 / p>

答案 2 :(得分:8)

我不确定我会依赖语言结构来增强系统的安全性。

我不认为制作一个字段最终会增加安全性来抵御恶意攻击(更可能是针对错误,当然还有线程问题)。安全性的唯一“真实形式”是,如果您有一个最终的常量字段,它可能会在编译时被内联,因此在运行时更改其值将没有任何影响。

我在继承的背景下听说过最终和安全性。通过使一个类最终,你可以阻止某人继承它并触摸或覆盖其受保护的成员,但我再次使用它来避免错误而不是防止威胁。

答案 3 :(得分:4)

一般而言,最终,私人和其他此类构造应被视为一般性偏好陈述,而不是严格执行的安全性。

但是,如果您控制JVM正在运行该进程(比如您运行JVM上其他人提供的代码),那么final和private确实提供了安全性 - 再加上Java的SecurityManager。你可以通过反思来解决这些限制。

你不能做的是运送代码在其他人的JVM上运行,并认为你以这种方式隐藏任何东西。

编辑:Tom提醒我,序列化攻击(故意提供序列化数据的错误二进制流)也可以部分地通过正确使用final字段来防止。有效的Java有更多这样的例子。

答案 4 :(得分:4)

防范什么?

就移动代码而言(可以在系统之间移动的代码 - applet,midlet,WebStart,RMI / JINI等),这非常重要。应用于类,并在较小程度上可访问的方法,它可以防止恶意实现。与可访问的字段类似,值得注意的静态。如果您要编写可能成为库的一部分的代码,您需要敏锐地意识到这一点。

对于典型的,例如,网络或桌面应用程序代码,它远没那么重要。但是,它在字段上的缺失使得代码更难以阅读并且表明程序员感到困惑。这样的代码不太可能只是因为编写得很糟糕而安全。

答案 5 :(得分:3)

它不会使您的代码更安全,它更多地用于线程安全而不是其他任何东西。如果变量标记为final,则必须在创建对象时为其分配值。创建对象后,不能使该变量引用另一个值。

此行为允许您推断对象的状态,并在多个线程同时访问对象时做出某些假设。

答案 6 :(得分:2)

我想当有人说final使你的代码更安全时会有什么意思,它会阻止未来的开发人员出现并修改那些不打算修改的值,或继承不是旨在扩展(并在此过程中导致不可预测的结果)。它(直接)与身份验证没有任何关系。

答案 7 :(得分:2)

我非常确定final是一个设计构造,与访问修饰符在类声明中的方式大致相同 - 它是表达和实施设计的一种方式。

答案 8 :(得分:1)

更多的是“改变”东西而不是“保护”。最终的关键字只是放弃了改变/修改/扩展任何方法的能力。

答案 9 :(得分:1)

Final还可以改善性能/内存管理。

答案 10 :(得分:1)

“final”关键字确实具有一些安全隐患。想象一下,你正在设计一个安全的系统,它有一个服务,给定一个字符串,当且仅当字符串有效时才会执行某些操作。你可以写:

public void doSomethingUseful(String argument) {
    checkValidity(argument);
    /* prepare to do something useful... preparation takes a bit of time! */
    reallyDoTheUsefulTask(argument);
}

如果String不是最终的,一些聪明的攻击者可以继承String。它们的字符串不像库存String类那样是不可变的 - 实际上,它们可以产生另一个线程并尝试通过在checkValidity之后但在实际使用参数之前更改参数来对您的方法进行攻击。然后你的“有用任务”突然做了一些完全错误的事情,可能会危及安全性。他们刚绕过你的支票!但是,因为java.lang.String是final,所以你可以很好地保证当你要求一个String参数时,它实际上是标准的不可变String。这是一个非常重要的事情 - 基于使用系统调用进行不正确的参数处理,存在一整类内核模式攻击。

所以是的,final可以有一些安全性考虑。

答案 11 :(得分:1)

最终关键字通常用于保持不变性。对类或方法使用final是为了防止方法之间的联系被破坏。例如,假设类X的某些方法的实现假定方法M将以某种方式运行。将X或M声明为final将阻止派生类重新定义M,从而导致X行为不正确。它可以保护对象和方法不被操纵。但至于加密目的,使用final关键字不是解决方案