سطح مقدماتی (Beginner Level)
زمانی که شما برنامههای تحت کنسول (CLI) مینویسید، اغلب نیاز دارید که اطلاعات حساسی مانند «رمز عبور» یا «API Key» را از کاربر دریافت کنید. استفاده از تابع معمولی input() در پایتون باعث میشود که هر چه کاربر تایپ میکند، روی صفحه نمایش داده شود. این موضوع از نظر امنیتی (به خصوص اگر کسی کنار کاربر ایستاده باشد) خطرناک است.
ماژول استاندارد getpass برای حل این مشکل طراحی شده است. این ماژول به شما اجازه میدهد ورودی را دریافت کنید بدون اینکه کاراکترهای تایپ شده در ترمینال چاپ شوند (مانند زمان لاگین کردن در لینوکس).
استفاده از getpass
تابع getpass.getpass() دقیقا مانند input() عمل میکند، با این تفاوت که اکو (Echo) کردن کاراکترها را غیرفعال میکند.
نکته مهم: این کدها باید در ترمینال یا CMD اجرا شوند. در محیطهای IDE مثل PyCharm یا ژوپیتر نوتبوک، ممکن است این ماژول به درستی کار نکند یا با یک هشدار امنیتی مواجه شوید.
# Static code (Requires user interaction unavailable in pre-render)
import getpass
# دریافت رمز عبور بدون نمایش آن روی صفحه
password = getpass.getpass()
print("Password received successfully!")
شخصیسازی پیام (Prompt)
به طور پیشفرض، این تابع عبارت Password: را نمایش میدهد. شما میتوانید متن دلخواه خود را به عنوان آرگومان به آن پاس دهید.
# Static code
import getpass
# تعیین پیام دلخواه برای کاربر
api_key = getpass.getpass(prompt="Please enter your secure API Key: ")
# بررسی طول کلید (صرفاً برای مثال)
if len(api_key) > 10:
print("API Key looks valid.")
else:
print("Invalid Key.")
مثال کاربردی: سیستم لاگین ساده
در این مثال یک سیستم لاگین بسیار ساده را پیادهسازی میکنیم که نام کاربری را به صورت عادی و رمز عبور را به صورت مخفی دریافت میکند.
# Static code (Example: Simple CLI Login)
import getpass
def login():
username = input("Username: ")
# رمز عبور مخفی میماند
password = getpass.getpass("Password: ")
if username == "admin" and password == "secret123":
print("Welcome back, Admin!")
else:
print("Access Denied.")
if __name__ == "__main__":
login()
سطح پیشرفته (Professional Level)
ماژول getpass علاوه بر دریافت رمز عبور، قابلیتهای دیگری برای تعامل با محیط سیستم عامل و مدیریت جریانهای ورودی/خروجی (Streams) دارد. در سطح حرفهای باید بدانید که این ماژول چگونه محیط را تشخیص میدهد و در صورت بروز خطا چه واکنشی نشان میدهد.
دریافت نام کاربری سیستم (getuser)
تابع getpass.getuser() نام کاربری (Logname) کسی که در حال حاضر اسکریپت را اجرا میکند از متغیرهای محیطی سیستم عامل استخراج میکند.
این تابع به ترتیب متغیرهای محیطی زیر را بررسی میکند:
LOGNAMEUSERLNAMEUSERNAME
این قابلیت برای اسکریپتهای اتوماسیون که نیاز به دانستن کاربر جاری دارند بسیار مفید است.
مدیریت Stream و خطاهای احتمالی
تابع getpass() به طور پیشفرض سعی میکند به /dev/tty (در یونیکس) متصل شود تا ورودی و خروجی را کنترل کند. اگر آرگومان stream تعیین شود، پیام (Prompt) در آن جریان نوشته میشود (به جای stdout).
1. Fallback Mechanism
اگر getpass نتواند تنظیمات ترمینال را برای مخفی کردن اکو (Echo) تغییر دهد (مثلاً در یک محیط غیر تعاملی یا برخی Shellهای خاص)، به صورت خودکار یک هشدار چاپ میکند و سعی میکند اطلاعات را از sys.stdin بخواند، که ممکن است باعث شود رمز عبور دیده شود.
برای مدیریت این حالت در برنامههای حرفهای، باید استثنای getpass.GetPassWarning را مدیریت کنید یا جریان خروجی را کنترل نمایید.
# Static code (Demonstrating stream redirection)
import getpass
import sys
def secure_input_with_stderr():
print("Ready to accept input...")
try:
# ارسال پیام به stderr به جای stdout
p = getpass.getpass(prompt="Secure Input: ", stream=sys.stderr)
return p
except Exception as e:
return f"Error occurred: {e}"
2. نکات امنیتی حافظه (Memory Security)
یک نکته بسیار حرفهای که باید بدانید:
پایتون (و اکثر زبانهای سطح بالا) رشتهها (Strings) را به صورت Immutable (غیر قابل تغییر) مدیریت میکند. وقتی شما از getpass استفاده میکنید، رمز عبور به عنوان یک رشته معمولی در حافظه ذخیره میشود.
حتی پس از اینکه متغیر password از دسترس خارج شود (Garbage Collected)، لاشه آن ممکن است تا مدتی در حافظه RAM باقی بماند تا زمانی که پایتون آن بخش از حافظه را بازنویسی کند.
- Best Practice: برای برنامههای فوق امنیتی (نظامی/بانکی)، استفاده از زبانهایی که مدیریت حافظه مستقیم دارند (مثل C یا Rust) یا استفاده از کتابخانههایی که اجازه پاکسازی بافر حافظه را میدهند، ترجیح داده میشود. اما برای اکثر کاربردهای عمومی و وب،
getpassاستاندارد و کافی است.
مثال ترکیبی: ساخت CLI با تشخیص کاربر
در این مثال حرفهای، ما نام کاربر را از سیستم میگیریم و فقط رمز عبور را میپرسیم.
# Static code (Advanced CLI Logic)
import getpass
def auto_login_cli():
# تشخیص خودکار نام کاربری سیستم
current_user = getpass.getuser()
print(f"Detected user: {current_user}")
# درخواست رمز برای همان کاربر
try:
pwd = getpass.getpass(f"Enter password for {current_user}: ")
if not pwd:
print("Error: Password cannot be empty.")
return
# فرض کنید اینجا عملیات احراز هویت انجام میشود
print(f"Authenticating user '{current_user}'...")
# Security: Never print the password in logs!
except getpass.GetPassWarning:
print("Warning: Password might be visible in this terminal.")
if __name__ == "__main__":
auto_login_cli()