PRNG ضعیف

دسته OWASP: MASVS-CRYPTO: رمزنگاری

نمای کلی

مولد اعداد شبه تصادفی (PRNG) الگوریتمی است که توالی اعداد قابل پیش بینی را بر اساس یک مقدار شروع به نام seed تولید می کند. یک دنباله اعداد تولید شده توسط PRNG تقریباً همان ویژگی های یک دنباله اعداد تصادفی واقعی را دارد، اما ایجاد آن سریعتر و از نظر محاسباتی هزینه کمتری دارد.

به عبارت دیگر، PRNG ها از نظر یکنواختی توزیع آنتروپی، که دنباله های اعداد واقعا تصادفی را تقلید می کنند، نسبت به RNG های ضعیف (مثلاً java.math.Random ) اطمینان بیشتری دارند. تولید اعداد تصادفی واقعاً به تجهیزات تخصصی نیاز دارد و اغلب خارج از محدوده توسعه عادی است. این مقاله تولید اعداد واقعا تصادفی را پوشش نمی‌دهد و تنها بر روی PRNG تمرکز می‌کند، زیرا آنها روش استاندارد در حال استفاده هستند.

آسیب‌پذیری‌های ضعیف PRNG زمانی رخ می‌دهند که توسعه‌دهندگان از یک PRNG معمولی برای مقاصد رمزنگاری استفاده می‌کنند، به جای یک PRNG امن رمزنگاری (CSPRNG). CSPRNG ها الزامات سخت گیرانه تری دارند، و وقتی seed ناشناخته است، باید به مهاجم فقط یک مزیت ناچیز در تمایز یک توالی خروجی از یک دنباله تصادفی واقعی بدهد.

مهاجمان همچنین ممکن است بتوانند دنباله اعداد تولید شده را حدس بزنند زمانی که دانه‌های قابل پیش‌بینی - مانند آنهایی که توسط توسعه‌دهنده کدگذاری شده‌اند - برای مقداردهی اولیه یک PRNG یا CSPRNG استفاده می‌شوند، زیرا مهاجم می‌تواند seed را حدس بزند و بنابراین خروجی تولید شده توسط PRNG را پیش‌بینی کند.

تاثیر

اگر یک PRNG غیر رمزنگاری امن در یک زمینه امنیتی مانند احراز هویت استفاده شود، مهاجم ممکن است بتواند اعداد تولید شده به طور تصادفی را حدس بزند و به داده‌ها یا عملکردهای ممتاز دسترسی پیدا کند.

اقدامات کاهشی

ژنرال

java.security.SecureRandom

برای مصارف امنیتی توصیه می شود . اگر نسخه هسته لینوکس 5.17+ است یا مسدود کردن رشته قابل قبول است، منتظر بمانید تا آنتروپی کافی جمع شود قبل از اینکه اعداد تصادفی را ایجاد کنید (یعنی از /dev/random استفاده کنید). برای انجام این کار، getInstanceStrong() را فراخوانی کنید:

کاتلین

val rand = SecureRandom.getInstanceStrong()

جاوا

SecureRandom rand = SecureRandom.getInstanceStrong();

در غیر این صورت، در نسخه‌های هسته لینوکس قبل از 5.17، زمانی که مسدود کردن رشته در هنگام تولید اعداد تصادفی غیرقابل قبول است، پس سازنده SecureRandom باید مستقیماً فراخوانی شود:

کاتلین

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

جاوا

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 دریافت می‌کند، و به‌طور خودکار زمانی که شی ساخته یا به‌دست می‌آید استفاده می‌شود، بنابراین نیازی به seed کردن صریح PRNG نیست. به طور کلی، هرگونه استفاده قطعی از SecureRandom ممنوع است (مخصوصاً اگر این امر منجر به کدنویسی یک مقدار seed شود، که هر کسی که برنامه را دیکامپایل کند می تواند ببیند). توسعه دهندگانی که می خواهند خروجی شبه تصادفی تکرار شونده تولید کنند باید از اولیه های مناسب تری مانند HMAC، HKDF، SHAKE و غیره استفاده کنند.

java.util.Random

برای اهداف امنیتی / احراز هویت اجتناب کنید ، قابل استفاده برای هر چیز دیگری است.

کاتلین

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

جاوا

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

منابع