PRNG ไม่ดี

หมวดหมู่ OWASP: MASVS-CRYPTO: วิทยาการเข้ารหัสลับ

ภาพรวม

โปรแกรมสร้างตัวเลขสุ่ม (PRNG) เป็นอัลกอริทึมที่สร้าง ลำดับตัวเลขที่คาดการณ์ได้ตามค่าเริ่มต้นที่เรียกว่า seed ต ลำดับตัวเลขที่ PRNG สร้างขึ้นมีพร็อพเพอร์ตี้โดยประมาณเหมือนกับ ลำดับตัวเลขแบบสุ่มอย่างแท้จริง แต่เร็วกว่าและประหยัดในการคำนวณ ในการสร้าง

กล่าวคือ PRNG มีความน่าเชื่อถือสูงกว่า RNG แบบอ่อน (เช่น java.math.Random) ในแง่ความสม่ำเสมอของการแจกแจงข้อมูลความผันผวน ซึ่งจำลองลำดับตัวเลขแบบสุ่มอย่างแท้จริง การสร้างตัวเลขแบบสุ่มที่แท้จริงจำเป็นต้องใช้ อุปกรณ์พิเศษและมักจะอยู่นอกขอบเขตของการพัฒนาตามปกติ ช่วงเวลานี้ เอกสารไม่ครอบคลุมการสร้างตัวเลขแบบสุ่มอย่างแท้จริง และมุ่งเน้นที่ PRNG เนื่องจากเป็นวิธีการมาตรฐานที่ใช้

ช่องโหว่ PRNG ที่อ่อนเกิดขึ้นเมื่อนักพัฒนาซอฟต์แวร์ใช้ PRNG ปกติสำหรับ จุดประสงค์ในการเข้ารหัส แทน PRNG ที่ปลอดภัยแบบเข้ารหัสลับ (CSPRNG) CSPRNG มีข้อกำหนดที่เข้มงวดกว่า และเมื่อไม่ทราบข้อมูลเมล็ดพันธุ์ ข้อมูลดังกล่าวต้องให้ข้อได้เปรียบที่ไม่สําคัญต่อผู้โจมตีในการแยกแยะลําดับเอาต์พุตออกจากลําดับแบบสุ่มจริง

ผู้โจมตีอาจเดาลำดับตัวเลขที่สร้างขึ้นได้ด้วยเมื่อใช้เมล็ดพันธุ์ที่คาดเดาได้ เช่น เมล็ดพันธุ์ที่นักพัฒนาซอฟต์แวร์เขียนโค้ดไว้อย่างเจาะจง เพื่อเริ่มต้น PRNG หรือ CSPRNG เนื่องจากผู้โจมตีสามารถเดาเมล็ดพันธุ์และคาดเดาเอาต์พุตที่ PRNG สร้างขึ้นได้

ผลกระทบ

หากมีการใช้ PRNG ที่ไม่มีการเข้ารหัสลับในบริบทด้านความปลอดภัย เช่น อาจทำให้ผู้โจมตีคาดเดาตัวเลขที่สร้างขึ้นแบบสุ่มได้ และรับสิทธิ์เข้าถึงข้อมูลหรือฟีเจอร์ที่เป็นสิทธิ์เฉพาะบุคคล

การลดปัญหา

ทั่วไป

java.security.SecureRandom

แนะนำสำหรับการใช้งานด้านความปลอดภัย หากเคอร์เนล Linux เป็นเวอร์ชัน 5.17 ขึ้นไป หรืออนุญาตให้บล็อกเธรดได้ ให้รอให้ข้อมูลสุ่มสะสมมากพอก่อนที่จะสร้างตัวเลขสุ่ม (เช่น ใช้ /dev/random) โดยเรียกใช้ getInstanceStrong() ดังนี้

Kotlin

val rand = SecureRandom.getInstanceStrong()

Java

SecureRandom rand = SecureRandom.getInstanceStrong();

หรือในเคอร์เนล Linux เวอร์ชันก่อน 5.17 เมื่อบล็อกเธรดเพื่อสร้างเลขสุ่มไม่ได้ คุณควรเรียกSecureRandomคอนสตรัคเตอร์ SecureRandom โดยตรง ดังนี้

Kotlin

import java.security.SecureRandom

object generateRandom {
    @JvmStatic
    fun main(args: Array<String>) {
        // Create instance of SecureRandom class
        val rand = SecureRandom()

        // Generate random integers in range 0 to 999
        val rand_int = rand.nextInt(1000)

        // Use rand_int for security & authentication
    }
}

Java

import java.security.SecureRandom;

public class generateRandom {

    public static void main(String args[])
    {
        // Create instance of SecureRandom class
        SecureRandom rand = new SecureRandom();

        // Generate random integers in range 0 to 999
        int rand_int = rand.nextInt(1000);

        // Use rand_int for security & authentication
    }
}

SecureRandom ได้รับค่าตั้งต้นจาก /dev/urandom และจะดำเนินการโดยอัตโนมัติ ใช้เมื่อมีการสร้างหรือได้วัตถุนั้นขึ้น ดังนั้นจึงไม่จำเป็นต้อง ตั้ง PRNG อย่างชัดเจน โดยทั่วไปแล้ว การใช้งานเชิงกำหนดของ SecureRandom (โดยเฉพาะอย่างยิ่งถ้าวิธีนี้นำไปสู่ การฮาร์ดโค้ดค่าตั้งต้น ซึ่ง ทุกคนที่คอมไพล์แอปจะเห็น) นักพัฒนาแอปที่ต้องการสร้างเอาต์พุตแบบสุ่มจำลองที่ซ้ำกันได้ควรใช้องค์ประกอบพื้นฐานที่เหมาะสมกว่า เช่น HMAC, HKDF และ SHAKE

java.util.Random

หลีกเลี่ยง เพื่อวัตถุประสงค์ด้านความปลอดภัย / การตรวจสอบสิทธิ์ ซึ่งใช้ได้หลายวัตถุประสงค์ ทั้งหมด

Kotlin

import java.util.Random

object generateRandom {
    @JvmStatic
    fun main(args: Array<String>) {
        // Create instance of SecureRandom class
        val rand = Random()

        // Generate random integers in range 0 to 999
        val rand_int = rand.nextInt(1000)
    }
}

Java

import java.util.Random;

public class generateRandom {

    public static void main(String args[])
    {
        // Create instance of Random class
        Random rand = new Random();

        // Generate random integers in range 0 to 999
        int rand_int = rand.nextInt(1000);
    }
}

แหล่งข้อมูล