secrets --- تولید اعداد تصادفی امن برای مدیریت اسرار

اضافه شده در نسخه‌ی 3.6.

کد منبع: Lib/secrets.py


ماژول secrets برای تولید اعداد تصادفی قوی از نظر رمزنگاری استفاده می‌شود که برای مدیریت داده‌هایی مانند گذرواژه‌ها، احراز هویت حساب، توکن‌های امنیتی و رازهای مرتبط مناسب هستند.

به‌طور خاص، secrets باید به‌جای مولد عدد شبه‌تصادفی پیش‌فرض در ماژول random استفاده شود؛ زیرا آن مولد برای مدل‌سازی و شبیه‌سازی طراحی شده است، نه برای امنیت یا رمزنگاری.

همچنین ملاحظه نمائید

PEP 506

اعداد تصادفی

ماژول secrets دسترسی به امن‌ترین منبع تصادف را که سیستم‌عامل شما ارائه می‌دهد، فراهم می‌کند.

class secrets.SystemRandom

کلاسی برای تولید اعداد تصادفی با استفاده از باکیفیت‌ترین منابع ارائه‌شده توسط سیستم‌عامل. برای جزئیات بیشتر، random.SystemRandom را ببینید.

secrets.choice(seq)

یک عنصر انتخاب‌شده به‌صورت تصادفی از یک دنباله‌ی غیرخالی برمی‌گرداند.

secrets.randbelow(exclusive_upper_bound)

یک عدد صحیح تصادفی در بازه‌ی [0, exclusive_upper_bound) برمی‌گرداند.

secrets.randbits(k)

یک عدد صحیح نامنفی با k بیت تصادفی برمی‌گرداند.

تولید توکن‌ها

ماژول secrets توابعی برای تولید توکن‌های امن فراهم می‌کند که برای کاربردهایی مانند بازنشانی گذرواژه، URLهایی که حدس زدن آن‌ها دشوار است و موارد مشابه مناسب هستند.

secrets.token_bytes(nbytes=None)

یک رشته بایت تصادفی شامل تعداد nbytes بایت برمی‌گرداند.

اگر nbytes مشخص نشده باشد یا None باشد، به‌جای آن از DEFAULT_ENTROPY استفاده می‌شود.

>>> token_bytes(16)
b'\xebr\x17D*t\xae\xd4\xe3S\xb6\xe2\xebP1\x8b'
secrets.token_hex(nbytes=None)

یک رشته متنی تصادفی را به‌صورت مبنای شانزده برمی‌گرداند. این رشته nbytes بایت تصادفی دارد که هر بایت به دو رقم مبنای شانزده تبدیل می‌شود.

اگر nbytes مشخص نشده باشد یا None باشد، به‌جای آن از DEFAULT_ENTROPY استفاده می‌شود.

>>> token_hex(16)
'f9bf78b9a18ce6d46a0cd2b0b86df9da'
secrets.token_urlsafe(nbytes=None)

یک رشته متنی تصادفی و امن برای URL برمی‌گرداند که شامل nbytes بایت تصادفی است. این متن به‌صورت Base64 کدگذاری‌شده است، بنابراین به‌طور میانگین هر بایت تقریباً معادل ۱٫۳ نویسه می‌شود.

اگر nbytes مشخص نشده باشد یا None باشد، به‌جای آن از DEFAULT_ENTROPY استفاده می‌شود.

>>> token_urlsafe(16)
'Drmhze6EPcv0fN_81Bj-nA'

توکن‌ها باید از چند بایت استفاده کنند؟

برای ایمن بودن در برابر حملات جستجوی فراگیر (brute-force attacks)، توکن‌ها باید از تصادفی‌بودن کافی برخوردار باشند. متأسفانه، آنچه کافی در نظر گرفته می‌شود لزوماً با قدرتمندتر شدن کامپیوترها و توانایی آن‌ها برای انجام حدس‌های بیشتر در بازه‌ی زمانی کوتاه‌تر، افزایش خواهد یافت. از سال ۲۰۱۵، تصور می‌شود که ۳۲ بایت (۲۵۶ بیت) تصادفی‌بودن برای مورد استفاده‌ی معمولی که از ماژول secrets انتظار می‌رود، کافی است.

اگر می‌خواهید طول توکن‌های خود را مدیریت کنید، می‌توانید با دادن یک آرگومان int به توابع مختلف token_*، به‌صراحت مشخص کنید که چه میزان تصادفی بودن برای توکن‌ها استفاده می‌شود. آن آرگومان به‌عنوان تعداد بایت‌های تصادفی برای استفاده در نظر گرفته می‌شود.

در غیر این صورت، اگر هیچ آرگومانی ارائه نشود، یا اگر آرگومان None باشد، توابع token_* به‌جای آن از DEFAULT_ENTROPY استفاده می‌کنند.

secrets.DEFAULT_ENTROPY

تعداد پیش‌فرض بایت‌های تصادفی که توسط توابع token_* استفاده می‌شود.

مقدار دقیق ممکن است در هر زمانی، از جمله در نسخه‌های نگهداری، تغییر کند.

توابع دیگر

secrets.compare_digest(a, b)

اگر رشته‌ها یا اشیای شبه‌بایت a و b برابر باشند، True را برمی‌گرداند، در غیر این صورت False را برمی‌گرداند و برای کاهش خطر حملات زمان‌سنجی از «مقایسه با زمان ثابت» استفاده می‌کند. برای جزئیات بیشتر، hmac.compare_digest() را ببینید.

دستورعمل‌ها و بهترین روش‌ها

این بخش، دستور پخت‌ها و بهترین شیوه‌ها را برای استفاده از secrets جهت مدیریت یک سطح پایه از امنیت نشان می‌دهد.

تولید یک گذرواژه‌ی الفبایی‌عددی هشت‌نویسه‌ای:

import string
import secrets
alphabet = string.ascii_letters + string.digits
password = ''.join(secrets.choice(alphabet) for i in range(8))

توجه

برنامه‌ها نباید رمزهای عبور را در قالبی قابل‌بازیابی ذخیره کنند، چه به‌صورت متن ساده و چه به‌صورت رمزنگاری‌شده. این رمزهای عبور باید با استفاده از یک تابع هش یک‌طرفه (غیرقابل‌بازگشت) و قوی از نظر رمزنگاری، نمک‌گذاری و هش‌دهی شوند.

یک گذرواژه الفبایی‌عددی ۱۰ نویسه‌ای با دست‌کم ۱ نویسه کوچک، دست‌کم ۱ نویسه بزرگ و دست‌کم ۳ رقم تولید کنید:

import string
import secrets
alphabet = string.ascii_letters + string.digits
while True:
    password = ''.join(secrets.choice(alphabet) for i in range(10))
    if (any(c.islower() for c in password)
            and any(c.isupper() for c in password)
            and sum(c.isdigit() for c in password) >= 3):
        break

یک عبارت عبور به سبک XKCD تولید کنید:

import secrets
# On standard Linux systems, use a convenient dictionary file.
# Other platforms may need to provide their own word-list.
with open('/usr/share/dict/words') as f:
    words = [word.strip() for word in f]
    password = ' '.join(secrets.choice(words) for i in range(4))

یک URL موقت که حدس زدن آن دشوار است و حاوی یک توکن امنیتی مناسب برای برنامه‌های بازیابی گذرواژه است، تولید کنید:

import secrets
url = 'https://example.com/reset=' + secrets.token_urlsafe()