Arrays.equals() vs MessageDigest.isEqual()

English 简体中文 ภาษาไทย Tiếng Việt
Summary

When comparing byte arrays, developers often choose between Arrays.equals() and MessageDigest.isEqual(), each with distinct characteristics. Arrays.equals() prioritizes efficiency by failing fast, returning immediately upon the first differing byte, but this non-constant time behavior can expose systems to timing attacks, especially in security-sensitive contexts like key or hash comparisons. Conversely, MessageDigest.isEqual() performs a time-constant comparison, iterating through all bytes regardless of early mismatches, which prioritizes security over raw speed. Therefore, the choice hinges on the application's needs: opt for Arrays.equals() when efficiency is paramount, but always use MessageDigest.isEqual() for cryptographic or security-critical comparisons to mitigate timing attack risks.

ทั้ง Arrays.equals() และ MessageDigest.isEqual() ใช้สำหรับเปรียบเทียบความเท่ากันของอาร์เรย์สองตัว สามารถใช้แทนกันได้ในหลายกรณี อย่างไรก็ตาม พวกมันมีความแตกต่างบางอย่างที่นำไปสู่การใช้งานที่แตกต่างกันในแอปพลิเคชันจริง

ความแตกต่างอย่างหนึ่งคือ อาร์เรย์ที่ส่งผ่านไปยัง MessageDigest.isEqual() ไม่สามารถเป็น null ได้ ในขณะที่ Arrays.equals() สามารถเป็นได้

ความแตกต่างที่สำคัญอย่างหนึ่งระหว่างเมธอดทั้งสองนี้คือ Arrays.equals() ไม่ใช่ time-constant ในขณะที่ MessageDigest.isEqual() เป็น time-constant นั่นหมายความว่าเมื่อเปรียบเทียบอาร์เรย์สองตัว อาร์เรย์จะถูกเปรียบเทียบทีละไบต์ Arrays.equals() จะส่งคืนทันทีสำหรับไบต์แรกที่ไม่เท่ากัน MessageDigest.isEqual() จะเปรียบเทียบไบต์ทั้งหมดในอาร์เรย์ไม่ว่าไบต์แรกจะไม่เท่ากันที่ตำแหน่งใด

การใช้งานของ Arrays.equals() คือ :

public static boolean equals(byte[] a, byte[] a2) {
    if (a==a2)
        return true;
    if (a==null || a2==null)
        return false;

    int length = a.length;
    if (a2.length != length)
        return false;

    for (int i=0; i<length; i++)
        if (a[i] != a2[i])
            return false;

    return true;
}

จากลูป for Arrays.equals() เป็นเมธอด fail fast ถ้าไบต์แรกไม่เท่ากัน มันจะส่งคืนทันที โดยปกติแล้วหมายถึงประสิทธิภาพสูงแต่ความปลอดภัยน้อยกว่า จริงๆแล้วจากการใช้งาน เมธอดนี้ถูกออกแบบมาเพื่อประสิทธิภาพ พวกมันมีการตรวจสอบไม่กี่อย่างเพื่อตรวจสอบว่าอาร์เรย์สองตัวเท่ากันอย่างรวดเร็วโดยไม่ต้องเปรียบเทียบเนื้อหาของอาร์เรย์จริงๆ

การใช้งานของ MessageDigest.isEqual() คือ :

public static boolean isEqual(byte[] digesta, byte[] digestb) {
    if (digesta.length != digestb.length) {
        return false;
    }

    int result = 0;
    // time-constant comparison
    for (int i = 0; i < digesta.length; i++) {
        result |= digesta[i] ^ digestb[i];
    }
    return result == 0;
}

จากลูป for อาร์เรย์จะถูกเปรียบเทียบอย่างสมบูรณ์ นั่นหมายความว่าความปลอดภัยสูงแต่ประสิทธิภาพต่ำกว่า

ในระบบที่มีความต้องการด้านความปลอดภัยสูง Arrays.equals() อาจมีความเสี่ยงต่อการโจมตีแบบ time constant ตัวอย่างเช่น ถ้ามีการเปรียบเทียบแฮชหรือคีย์โดยใช้ Arrays.equals() การโจมตีสามารถปลอมแฮชหรือคีย์และทำการเปรียบเทียบกับแฮชหรือคีย์จริง พวกเขาสามารถวัดเวลาที่ใช้สำหรับ Arrays.equals() ในการส่งคืนเพื่อทำความเข้าใจว่ามีไบต์ที่ตรงกับแฮชหรือคีย์ปลอมกี่ไบต์ หลังจากลองหลายร้อยหรือหลายพันครั้ง พวกเขาอาจเปิดเผยแฮชและคีย์จริง สำหรับรายละเอียดเกี่ยวกับวิธีการโจมตีนี้ คุณสามารถอ่านเพิ่มเติมได้ที่ A Lesson In Timing Attacks (or, Don’t use MessageDigest.isEquals).

ดังนั้นเมื่อคุณตัดสินใจที่จะใช้เมธอดในการเปรียบเทียบอาร์เรย์สองตัว โปรดพิจารณาอย่างรอบคอบว่าแอปพลิเคชันนั้นเกี่ยวข้องกับความปลอดภัยหรือประสิทธิภาพหรือไม่ ถ้าสิ่งที่คุณต้องการคือประสิทธิภาพ ให้ใช้ Arrays.equals() แต่ถ้าคุณกำลังพัฒนาผลิตภัณฑ์ด้านความปลอดภัย โปรดระมัดระวังและใช้ MessageDigest.isDigest() ต่อไป

จำไว้ว่าแฮกเกอร์เป็นกลุ่มคนที่ "ใช้ทุกวิธีการที่นึกออก; ไม่หยุดยั้ง"

JAVA SECURITY ARRAYS.EQUAL() MESSAGEDIGEST.ISEQUAL()

  RELATED

  COMMENTS

0

No comment for this article.