Does the Java 'final' keyword actually imp

2019-02-16 08:19发布

问题:

While there are many reasons to use the 'final' keyword in Java, one of the ones I keep hearing over and over again is that it makes your code more secure. While this seems to make sense in this trivial case:

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

With the final keyword, you would expect that no malicious code would be able to change the variable passwordHash. However, using reflection it is possible to change the final modifier on the passwordHash field.

So does 'final' provide any real security, or is it just placebo?

Edit: There is some really interesting discussion, and I wish I could accept more than one answer. Thanks everyone for your input.

回答1:

It's not 'security' in the sense of 'withstanding an attack'; it's more like 'harder to mess up by mistake'.

I prefer the word 'safety'; i feel its more like preventing an accident, not malice.



回答2:

Java's final keyword is not used for this kind of security. It is not a substitute for what would normally require a cryptographic solution.

What is usually meant by "security" in these kinds of discussions is the concept of a secure object model - that is to say an object model that cannot be manipulated by consumers for purposes unintended by the original author of the class.



回答3:

I'm not sure I would rely on language constructs for added security in my system.

I don't think that making a field final would add security against malicious attacks (more likely against mistakes and of course threading issues). The only "real form" of security is that if you have a final constant field it might get inlined at compilation so changing its value at runtime would have no impact.

I've heard of final and security more in the context of inheritance. By making a class final you can prevent someone from subclassing it and touching or overriding its protected members, but again I would use that more to avoid mistake than to prevent threats.



回答4:

Secure against what?

In terms of mobile code (code that can move between systems - applets, midlets, WebStart, RMI/JINI, etc), it is very important. Applied to classes, and to a lesser extent accessible methods, it prevents malicious implementations. Similarly with accessible fields, notable statics. If you are going to write code that may become part of a library, you need to be keenly aware of this.

For typical, say, web or desktop app code, it is far less important. However, its absence on fields makes code more difficult to read and indicates a confused programmer. Such code is unlikely to be secure just because it is badly written.



回答5:

In general final, private and other such constructs should be considered more as general statements of preference, rather than strictly enforced security.

However, if you control the JVM the process is running on (say you run code provided by others on your JVM) then final and private do indeed provide security - coupled with Java's SecurityManager. The things you can do via reflection to get around these restrictions can be prevented.

What you can't do is ship code to run on someone else's JVM and think that you hide anything this way.

Edit: Tom reminds me that Serialization attacks (that is deliberately providing bad binary streams of serialized data) can also be prevented in part by proper use of final fields. Effective Java has more such examples.



回答6:

It doesn't make your code more secure, it is more for thread safety than anything else. If a variable is marked final, a value must be assigned to it when the object is created. After object creation, that variable cannot be made to refer to another value.

This behavior allows you to reason about the state of an object and make certain assumptions when multiple threads are accessing it concurrently.



回答7:

I imagine what someone would mean when they said that final makes your code more secure is that it prevents future developers from coming along and modifying values that are not meant to be modified, or inheriting from classes which are not designed to be extended (and causing unpredictable results in the process). It doesn't have anything to do (directly) with authentication.



回答8:

I am pretty sure final is a design construct in much the same way access modifiers are in a class declarations - it's a way to express and enforce design.



回答9:

It is more about "changing" the stuff rather than "securing". The final keywords simply puts away the ability to change/modify/extend any method.



回答10:

Final also improves performance/memory management.



回答11:

The "final" keyword does indeed have some security implications. Imagine you are designing a secure system which has a service that, given a string, does something if and only if the string is valid. You might write:

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

If String were not final, some clever attacker could subclass String. Their string is not immutable like the stock String class is - and in fact, they can spawn another thread and try to do attacks on your method by changing the argument after checkValidity but before you actually use the argument. Then your "useful task" suddenly does something completely wrong, possibly compromising security. They've just bypassed your checks! Because java.lang.String is final, however, you have good guarantees that when you ask for a String parameter it is, in fact, the standard immutable String. This is a pretty big deal - there was an entire class of kernel-mode attacks based around improper parameter handling with syscalls.

So yes, final can have some security considerations.



回答12:

Final keyword is usually used to preserve immutability. To use final for classes or methods is to prevent linkages between methods from being broken. For example, suppose the implementation of some method of class X assumes that method M will behave in a certain way. Declaring X or M as final will prevent derived classes from redefining M in such a way as to cause X to behave incorrectly. It secures objects and methods from getting manipulated. But as for cryptography purpose, using final keyword is not the solution