Effective java says:
// Potential security hole!
static public final Thing[] VALUES = { ... };
Can somebody tell me what is the security hole?
Use public final static String when you want to create a String that: belongs to the class ( static : no instance necessary to use it), that. won't change ( final ), for instance when you want to define a String constant that will be available to all instances of the class, and to other objects using the class, and ...
A public static final variable is a compile-time constant, but a public final is just a final variable, i.e. you cannot reassign value to it but it's not a compile-time constant. This may look puzzling, but the actual difference allows how the compiler treats those two variables.
Declaring static final public
fields is usually the hallmark of a class constant. It's perfectly fine for primitive types (ints, doubles etc..), and immutable classes, like strings and java.awt.Color
. With arrays, the problem is that even though the array reference is constant, the elements of the array can still be changed, and as it's a field, changes are unguarded, uncontrolled, and usually unwelcome.
To combat this, the visibility of the array field can be restricted to private or package private, so you have a smaller body of code to consider when looking for suspicious modification. Alternatively, and often better, is to do away with the array together and use a 'List', or other appropriate collection type. By using a collection, you control if updates are allowed, since all updates go through methods. You can prevent updates by wrapping your collection using Collections.unmodifiableList()
. But beware that even though the collection is immutable, you must also be sure that the types stored in it are also immutable, or the risk of unsolicited changes on a supposed constant will reappear.
To understand why this is a potential security hole and not just poor encapsulation, consider the following example:
public class SafeSites { // a trusted class with permission to create network connections public static final String[] ALLOWED_URLS = new String[] { "http://amazon.com", "http://cnn.com"}; // this method allows untrusted code to connect to allowed sites (only) public static void doRequest(String url) { for (String allowed : ALLOWED_URLS) { if (url.equals(allowed)) { // send a request ... } } } } public class Untrusted { // An untrusted class that is executed in a security sandbox. public void naughtyBoy() { SafeSites.ALLOWED_URLS[0] = "http://myporn.com"; SafeSites.doRequest("http://myporn.com"); } }
As you can see, the mistaken use of a final array means that untrusted code can subvert the restriction that the trusted code / sandbox is trying to impose. In this case, this is clearly a security issue.
If your code is not part of a security critical application, then you could ignore this issue. But IMO this is a bad idea. At some point in the future you (or someone else) might reuse your code in a context where security is a concern. At any rate, this is why the author calls public final arrays a security issue.
Amber said this in a comment:
No more a security hole than private would be, if you can read the source code and/or bytecode either way...
This is not true.
The fact that a "bad guy" can use source code / bytecodes to determine that a private
exists and refers to an array is not sufficient to break security. The bad guy also has to inject code into a JVM that has the required permissions to use reflection. This permission is not available to untrusted code running in a (properly implemented) security sandbox.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With