PRNG ضعیف

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

نمای کلی

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

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

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

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

تأثیر

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

کاهش

عمومی

java.security.SecureRandom

برای استفاده‌های امنیتی توصیه می‌شود. در Android، SecureRandom.getInstanceStrong() معادل دریافت SHA1PRNG از AndroidOpenSSL است. این مورد با پیاده‌سازی مسدودکننده /dev/random مطابقت ندارد. برای استفاده از آن، با getInstanceStrong() تماس بگیرید:

کاتلین

val rand = SecureRandom.getInstanceStrong()

جاوا

SecureRandom rand = SecureRandom.getInstanceStrong();

درغیراین‌صورت، در نسخه‌های هسته Linux قبل‌از ۵.۱۷، وقتی مسدود کردن رشته هنگام تولید اعداد تصادفی غیرقابل‌قبول است، سازنده 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 دریافت می‌کند و به‌طور خودکار هنگام ساخت یا دریافت شیء استفاده می‌شود، بنابراین نیازی به مقداردهی اولیه صریح PRNG نیست. به‌طور کلی، هرگونه استفاده قطعی از SecureRandom توصیه نمی‌شود (به‌ویژه اگر این امر منجر به کدگذاری سخت مقدار بنیادی شود، که هرکسی که برنامه را تبدیل کد می‌کند می‌تواند آن را ببیند). توسعه‌دهندگانی که می‌خواهند خروجی شبه‌تصادفی تکرارپذیر تولید کنند باید از دستورات پایه‌ای مناسب‌تری مثل 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);
    }
}

منابع