شعار PRNG ضعيف

فئة OWASP: MASVS-CRYPTO: التشفير

نظرة عامة

مولّد الأرقام العشوائية الزائفة (PRNG) هو خوارزمية تنشئ تسلسلات أرقام يمكن توقّعها استنادًا إلى قيمة بداية تُعرف باسم القيمة العشوائية. ويحتوي تسلسل الأرقام الذي ينشئه مولّد الأرقام العشوائية الزائفة على الخصائص نفسها تقريبًا التي يحتوي عليها تسلسل الأرقام العشوائية الحقيقية، ولكن يكون إنشاؤه أسرع وأقل تكلفة من الناحية الحسابية.

بعبارة أخرى، توفّر مولّدات الأرقام العشوائية الزائفة ضمانات أعلى من مولّدات الأرقام العشوائية الضعيفة (مثل java.math.Random) من حيث التوزيع المتساوي للإنتروبيا، ما يحاكي تسلسلات الأرقام العشوائية الحقيقية. ويتطلّب إنشاء أرقام عشوائية حقيقية معدّات متخصّصة، وغالبًا ما يكون خارج نطاق التطوير العادي. لا يتناول هذا المستند إنشاء أرقام عشوائية حقيقية، ويركّز فقط على مولّدات الأرقام العشوائية الزائفة لأنّها المنهجية العادية المستخدَمة.

تحدث الثغرات الأمنية في مولّدات الأرقام العشوائية الزائفة الضعيفة عندما يستخدم المطوّرون مولّد أرقام عشوائية زائفة عاديًا لأغراض التشفير، بدلاً من مولّد أرقام عشوائية زائفة آمن بطريقة مشفَّرة (CSPRNG). تفرض مولّدات الأرقام العشوائية الزائفة الآمنة بطريقة مشفَّرة متطلبات أكثر صرامة، وعندما تكون القيمة العشوائية غير معروفة، يجب ألا تمنح المهاجم سوى ميزة ضئيلة في التمييز بين تسلسل الإخراج وتسلسل عشوائي فعلي.

قد يتمكّن المهاجمون أيضًا من تخمين تسلسل الأرقام الذي تم إنشاؤه عند استخدام قيم عشوائية يمكن توقّعها، مثل تلك التي تم ترميزها بشكل ثابت من قِبل المطوّر، لتهيئة مولّد أرقام عشوائية زائفة أو مولّد أرقام عشوائية زائفة آمن بطريقة مشفَّرة، لأنّه يمكن للمهاجم تخمين القيمة العشوائية وبالتالي توقّع الإخراج الذي ينشئه مولّد الأرقام العشوائية الزائفة.

التأثير

إذا تم استخدام مولّد أرقام عشوائية زائفة غير آمن بطريقة مشفَّرة في سياق أمان مثل المصادقة، قد يتمكّن المهاجم من تخمين الأرقام التي تم إنشاؤها عشوائيًا والوصول إلى بيانات أو ميزات مميّزة.

الإجراءات المخفّفة

بنود عامة

java.security.SecureRandom

يُنصح باستخدامه لأغراض الأمان. على Android، يعادل SecureRandom.getInstanceStrong() الحصول على SHA1PRNG من AndroidOpenSSL. ولا يرتبط بتنفيذ حظر /dev/random. لاستخدامه، عليك استدعاء getInstanceStrong():

Kotlin

val rand = SecureRandom.getInstanceStrong()

Java

SecureRandom rand = SecureRandom.getInstanceStrong();

بخلاف ذلك، في إصدارات Linux kernel السابقة للإصدار 5.17، إذا كان حظر سلسلة المحادثات غير مقبول عند إنشاء أرقام عشوائية، يجب استدعاء أداة إنشاء 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، ويتم استخدامه تلقائيًا عند إنشاء الكائن أو الحصول عليه، لذا ما مِن حاجة إلى تحديد القيمة العشوائية لمولّد الأرقام العشوائية الزائفة بشكلٍ صريح. بشكلٍ عام، لا يُنصح بأي استخدام حتمي لـ 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);
    }
}

الموارد