سطح مقدماتی (Beginner Level)
زمانی که صحبت از تولید اعداد تصادفی در پایتون میشود، اکثر افراد به ماژول random فکر میکنند. اما برای کاربردهای امنیتی مانند تولید کلمه عبور (Password)، توکنهای احراز هویت (Auth Tokens) یا کلیدهای API، استفاده از random خطرناک است زیرا اعداد آن قابل پیشبینی هستند.
پایتون از نسخه 3.6 ماژول استاندارد secrets را معرفی کرد که مخصوص تولید اعداد تصادفی ایمن از نظر رمزنگاری (Cryptographically Strong) است.
۱. چرا random نه؟ و secrets بله؟
ماژول random برای شبیهسازی و بازیها طراحی شده است (شبهتصادفی). در مقابل، secrets مستقیماً از منبع آنتروپی سیستمعامل (مثل /dev/urandom در لینوکس) استفاده میکند که غیرقابل پیشبینی است.
۲. تولید توکنهای امن (Hex و URL-Safe)
یکی از رایجترین کاربردهای secrets تولید رشتههای تصادفی برای لینکهای ریست پسورد یا سشنها است.
token_hex(n): یک رشته هگزادسیمال برمیگرداند (هر بایت ۲ کاراکتر میشود).token_urlsafe(n): یک رشته Base64 برمیگرداند که برای استفاده در URL امن است.
۳. انتخاب و اعداد تصادفی امن
توابع choice و randbelow در این ماژول عملکردی مشابه ماژول random دارند اما با امنیت بالا.
سطح پیشرفته (Professional Level)
در سطح حرفهای، ماژول secrets فقط برای تولید رشته نیست؛ بلکه ابزاری حیاتی برای جلوگیری از حملات زمانبندی (Timing Attacks) و مدیریت کلاسهای سطح پایین تولید عدد تصادفی است.
۱. جلوگیری از حملات Timing Attack
هنگامی که دو رشته حساس (مانند توکن ارسالی کاربر و توکن واقعی در دیتابیس) را با عملگر == مقایسه میکنید، پایتون به محض دیدن اولین کاراکتر متفاوت، مقایسه را متوقف میکند. هکرها میتوانند با اندازهگیری دقیق زمان پاسخ سرور، کاراکتر به کاراکتر رمز را حدس بزنند.
تابع compare_digest زمان ثابتی را صرف مقایسه میکند، فارغ از اینکه تفاوت در کاراکتر اول باشد یا آخر.
۲. کلاس SystemRandom
ماژول secrets در واقع یک رابط سادهشده (Wrapper) بر روی کلاس random.SystemRandom است. اگر نیاز به توابع پیشرفتهتری از ماژول random دارید (مثل shuffle یا sample) که در secrets وجود ندارند اما باید امن باشند، میتوانید مستقیماً از SystemRandom استفاده کنید.
۳. بهترین روش تولید رمز عبور پیچیده (Best Practice)
برای تولید رمزهای عبور واقعی، صرفاً انتخاب تصادفی کافی نیست (ممکن است رمز تولید شده عدد یا نماد نداشته باشد). الگوی زیر یک روش استاندارد برای تضمین پیچیدگی رمز است:
import secrets
import string
def generate_strong_password(length=12):
# مجموعهای از تمام کاراکترهای ممکن
alphabet = string.ascii_letters + string.digits + string.punctuation
while True:
password = ''.join(secrets.choice(alphabet) for _ in range(length))
# بررسی شروط پیچیدگی (حداقل یک بزرگ، یک کوچک، یک عدد، یک نماد)
if (any(c.islower() for c in password)
and any(c.isupper() for c in password)
and any(c.isdigit() for c in password)
and any(c in string.punctuation for c in password)):
return password
# این کد نیاز به فراخوانی دارد تا اجرا شود
# print(generate_strong_password())
نکات فنی و پرفورمنس
- سرعت: تولید اعداد با
secretsکندتر ازrandomاست. برای شبیهسازیهای علمی (Monte Carlo) یا بازیها که نیاز به میلیونها عدد در ثانیه دارید، همچنان ازrandomیاnumpyاستفاده کنید.secretsفقط برای امنیت است. - بلاک شدن: در برخی سیستمهای قدیمی لینوکس، خواندن از
/dev/randomممکن است برنامه را تا زمان جمعآوری آنتروپی کافی بلاک کند (هرچند پایتون مدرن معمولاً از/dev/urandomاستفاده میکند که بلاک نمیشود). - URL Safe: همیشه برای توکنهای وب از
token_urlsafeاستفاده کنید تا با کاراکترهای غیرمجاز در URL (مثل+یا/در Base64 استاندارد) دچار مشکل نشوید.