java安全编码指南之:Mutability可变性

不要相信equals
我们知道在HashMap中怎么去查找一个key呢?先去找这个key的hash值,然后去判断key.equals方法是否相等,考虑下面这种情况:

private final Map extras = new HashMap<>();

    public void op(Window window) {
        Extra extra = extras.get(window);
    }

op方法接收一个Window对象,然后将其当成key从HashMap中取出对应的value。

如果,这个时候,我们有一个类A继承了Window,并且hash值和equals都和另外一个Window对象B相同,那么使用A这个key可以获取到B这个key存储的数据!

怎么解决这个问题呢?

Java中有一个特别的HashMap:IdentityHashMap,这个Map的key和value比较是用==而不是equals方法,所以可以有效的避免上面出现的问题。

private final Map extras = new IdentityHashMap<>();

    public void op(Window window) {
        Extra extra = extras.get(window);
    }

如果没有这样的Map可用,那么可以使用不可变对象作为key或者使用Window的私有变量,从而恶意攻击者无法获得这个变量。

public class Window {
/* pp */
class PrivateKey {
Window getWindow() {
return Window.this;
}
}
final PrivateKey privateKey = new PrivateKey();

        private final Map extras =
             new WeakHashMap<>();
        ...
    }

    public class WindowOps {
        public void op(Window window) {
            // Window.equals may be overridden,
            // but safe as we don't use it.
            Extra extra = extras.get(window.privateKey);
            ...
        }
    }

不要直接暴露可修改的属性
如果一个可变类中的某个属性确实需要暴露被外部使用,那么一定要将这个属性定义为private,并且使用wrapper方法将其包装起来。

如果直接暴露出去,那么基本上就没有权限控制可言,任何程序只要能够拿到你这个对象,就可以对属性进行修改。考虑下下面的应用方式,我们在修改state的方法中加入了一个参数校验和权限控制。

public final class WrappedState {
// private immutable object
private String state;

        // wrapper method
        public String getState() {
            return state;
        }

        // wrapper method
        public void setState(final String newState) {
            this.state = requireValidation(newState);
        }

        private static String requireValidation(final String state) {
            if (...) {
                throw new IllegalArgumentException("...");
            }
            return state;
        }
    }

public static fields应该被置位final
同样的,如果你是一个类变量,当然不希望这个变量会被任何人修改,那么需要将其置位final。

public class Files {
public static final String separator = “/”;
public static final String pathSeparator = “:”;
}
public static final field 应该是不可变的
如果类变量是public static final的,那么这个变量一定要是不可变的。

有人会问了,都定义成了final了,是不是就已经不可变了?

其实不然,比如我们定义了一个final的List,虽然这个list不能变化,但是list里面的值是可以变化的。我们需要将可变变量修改为不可变变量,如下所示:

import static java.util.Arrays.asList;
import static java.util.Collections.unmodifiableList;

public static final List names = unmodifiableList(asList(
“Fred”, “Jim”, “Sheila”
));
如果使用JDK9中引入的of()或者ofEntries()方法,可以直接创建不可修改的集合:

public static final List
names =
List.of(“Fred”, “Jim”, “Sheila”);
龙华大道1号http://www.kinghill.cn/LongHuaDaDao1Hao/index.html

你可能感兴趣的:(java安全编码指南之:Mutability可变性)