شعار PRNG ضعيف

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

نظرة عامة

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

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

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

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

التأثير

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

إجراءات التخفيف

بنود عامة

java.security.SecureSpam.

يُنصح به للاستخدامات الأمنية. إذا كان إصدار نواة Linux هو 5.17 أو إصدار أحدث أو كان حظر سلسلة المهام مقبولًا، انتظِر حتى تتراكم كمية كافية من التشويش قبل توليد الأرقام العشوائية (أي استخدام /dev/random). لإجراء ذلك، استخدِم getInstanceStrong():

Kotlin

val rand = SecureRandom.getInstanceStrong()

Java

SecureRandom rand = SecureRandom.getInstanceStrong();

بخلاف ذلك، في إصدارات نواة Linux التي يسبقها الإصدار 5.17، عندما يكون حظر سلسلة المهام غير مقبول عند إنشاء أرقام عشوائية، يجب استدعاء SecureRandom constructor مباشرةً:

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.Spam

تجنَّب استخدامها لأغراض الأمان أو المصادقة، ولكن يُسمح باستخدامها لأغراض أخرى.

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);
    }
}

المراجع