equals()
方法) 比較方塊化原始物件,可導致非預期的行為。equals()
方法,而不是 ==
和 !=
運算子。Java 規格載明有關方塊化轉換的資訊: Boolean
或 Byte
),則只會快取或記住某個範圍的值。對於值子集,使用 ==
或 !=
將會傳回正確的值,對於此子集之外的所有其他值,這會傳回物件位址的比較結果。
...
Integer mask0 = 100;
Integer mask1 = 100;
...
if (file0.readWriteAllPerms){
mask0 = 777;
}
if (file1.readWriteAllPerms){
mask1 = 777;
}
...
if (mask0 == mask1){
//assume file0 and file1 have same permissions
...
}
...
Example 1
中的程式碼使用 Integer
方塊化原始物件,來嘗試比較兩個 int
值。如果 mask0
和 mask1
同時等於 100
,則 mask0 == mask1
將會傳回 true
。但是,現在當 mask0
和 mask1
都等於 777
時,mask0 == maske1
將會傳回 false
,因為這些值不在這些方塊化原始物件的快取值範圍內。NaN
進行比較一律是錯誤。NaN
進行比較時,一律會估算為 false
,除了 !=
運算子之外,這個運算子一律會估算為 true
,因為 NaN
處於未排序狀態。NaN
。
...
if (result == Double.NaN){
//something went wrong
throw new RuntimeException("Something went wrong, NaN found");
}
...
result
不是 NaN
,不過使用 ==
運算子搭配 NaN
一律會產生值 false
,因此這項檢查永不會拋出異常。this
參考,這可進而導致弱點。
...
class User {
private String username;
private boolean valid;
public User(String username, String password){
this.username = username;
this.valid = validateUser(username, password);
}
public boolean validateUser(String username, String password){
//validate user is real and can authenticate
...
}
public final boolean isValid(){
return valid;
}
}
validateUser
函數和類別不是 final
,這表示它們可以被取代,然後將變數初始化為會取代此函數的子類別時,會允許規避 validateUser
功能。例如:
...
class Attacker extends User{
public Attacker(String username, String password){
super(username, password);
}
public boolean validateUser(String username, String password){
return true;
}
}
...
class MainClass{
public static void main(String[] args){
User hacker = new Attacker("Evil", "Hacker");
if (hacker.isValid()){
System.out.println("Attack successful!");
}else{
System.out.println("Attack failed");
}
}
}
Example 1
中的程式碼會列印「Attack successful!」,因為 Attacker
類別會覆寫從 User
超級類別之建構函式呼叫的 validateUser()
函數,並且 Java 會先查看子類別中是否有從建構函式呼叫的函數。
if (fitz == null) {
synchronized (this) {
if (fitz == null) {
fitz = new Fitzer();
}
}
}
return fitz;
Fitzer()
物件,但是又不希望每次呼叫此程式碼時都進行一次同步化。這就是所謂的 double-checked locking。Fitzer()
物件。請參閱 Double-Checked Locking is Broken 聲明以取得更多詳細資訊 [1]。inputReader
物件的輸入。如果一個攻擊者能提供執行惡意指令的 inputReader
實作,這個程式碼將無法區分物件是否為惡意版本。
if (inputReader.GetType().FullName == "CompanyX.Transaction.Monetary")
{
processTransaction(inputReader);
}
inputReader
物件的輸入。如果一個攻擊者能提供執行惡意指令的 inputReader
實作,這個程式碼將無法區分物件是否為惡意版本。
if (inputReader.getClass().getName().equals("com.example.TrustedClass")) {
input = inputReader.getInput();
...
}
inputReader
物件的輸入。如果一個攻擊者能提供執行惡意指令的 inputReader
實作,這個程式碼將無法區分物件是否為惡意版本。
if (inputReader::class.qualifiedName == "com.example.TrustedClass") {
input = inputReader.getInput()
...
}
finalize()
方法應該呼叫 super.finalize()
。finalize()
方法中呼叫 super.finalize()
方法是一種非常好的做法 [1]。super.finalize()
。
protected void finalize() {
discardNative();
}