وبلاگ فربد | Farbod Blog

توی این وبلاگ راجع به پروژه هام صحبت می کنم

ساخت پسورد منیجر با پایتون

  • ۳۲

سلام دوستان :)

توی پست امروز قراره یاد بگیریم چطوری یک پسوورد منیجر با پایتون بسازیم. برای اینکه رمز های خودمونو یادمون نره و همچنین توی یک مکان امن نگهشون داریم. حتما تا حالا اسم پسورد منیجر ها رو شنیدین یا با اونها کار کردین. پس با من همراه باشین.

خب! همینطور که میدونید ما نباید برای اکانت های مختلفمون رمز های یکسان انتخاب کنیم. برای اینکه اگر یکیشون لو بره همشون لو نرن! شاید بگید چرا باید رمز من لو بره؟ اما من بهتون تضمین میدم که احتمالش خیلی زیاده. چه data leak های بزرگ مثل linkedin که سر و صدا هم کرد؛ چه توییتر و تلگرام و... که به اون بزرگی نبودن. اما علاوه بر این ها اکانت های خیلی زیادی از پلتفرم هایی که فکرش هم نمیکنید روزانه لو میره و حتی شما هم میتونید بهشون دسترسی داشته باشید.... حالا اگر این اتفاق برای یکی از پلتفرم های شما افتاد بهتره که بقیشون هم لو نره و اطلاعاتتون در امان بمونه.

از این بحث گذشته، اگر بخواین برای تک تک اکانت هاتون رمز های مختلف داشته باشید حفظ کردن همه اونا خیلی سخته. احتمالا همتون الان توی سایت های مختلف بالای ۱۰ اکانت دارید و اگر رمز همشون یکی نباشه حفظ کردنشون سخته. البته باید بگم که به بهانه ی راحت حفظ کردن، رمز های کلیشه ای نذارید!

 هممون تاحالا به صورت مستقیم یا غیر مستقیم با پسورد منیجر ها کار کردیم. برای مثال وقتی که یک اکانت میسازید و مرورگرتون بهتون پیشنهاد ذخیره اون رمز رو میده. همین مکانیسم توی موبایل ها هم وجود داره. اما این پسورد منیجر ها چطور کار میکنن که احتمال هک شدنشون خیلی پایینه؟

پسورد منیجر ها مثل یک دیکشنری هستن. یک پسورد رو برای یک یوزرنیم ذخیره میکنن که کاربر میتونه بهشون دسترسی داشته باشه. اما برای اینکه این پسورد ها در امان باشن، با پروتکل های مختلفی رمزگذاری میشن. این رمزگذاری به این صورته که شما یک رمز مادر انتخاب میکنید که باید خیلی قوی باشه. همه ی رمز های دیگتون با این رمز مادر کد گذاری میشن و کسی که رمز اصلی شما رو نداشته باشه، حتی اگر به فایل پسورد هاتون هم دسترسی پیدا کنه، نمیتونه از این اطلاعات استفاده ای بکنه. البته پسورد اصلیو باید حفظ کنید یا روی کاغذ و خارج از دنیای دیجیتال توی جای امنی نگهش دارید. البته پسورد منیجر های مدرن پسورد های رمزنگاری شده شما رو توی دیتابیس خودشون نگه میدارن و شما اون اکانتی که دارید میشه کلیدی که باهاش پسورد هاتون باز میشن.نا گفته نماندکه همین موضوع ممکنه امنیتشو یکم پایین بیاره.

خب حالا پسورد منیجر ما قراره که محلی یا local باشه و روی کامپیوتر خودمون ذخیره شه. البته خودتون میتونید آنلاینش هم بکنید ولی ما الان قرار نیست همچین کاری بکنیم. پسورد منیجر ما خیلی ساده هست و رابط گرافیکی هم نداره. اما امنیتش شاید از خیلی پسورد منیجر ها بیشتر باشه.

بریم شروع کنیم. برای شروع کد، اول کتابخونه های مورد نظر رو نصب می کنیم. پس برای نصب توی ویندوز وارد cmd بشید و دستورات زیر رو وارد کنید:

pip install pyperclip cryptography

برای نصب توی لینوکس یا مک هم وارد ترمینال بشید و دستور زیر رو وارد کنید:

sudo pip3 install pyperclip cryptography

(بسته به سیستمتون میتونید روت باشید یا نباشید)

 

بریم سراغ کد. یک فایل به اسم password_manager.py درست کنید و داخلش کد های زیر رو قرار بدید که بریم سراغ توضیحات:

import json, hashlib, getpass, os, pyperclip, sys
from cryptography.fernet import Fernet


# Function for Hashing the Master Password.
def hash_password(password):
    sha256 = hashlib.sha256()
    sha256.update(password.encode())
    return sha256.hexdigest()


# Generate a secret key. This should be done only once as you'll see.
def generate_key():
    return Fernet.generate_key()


# Initialize Fernet cipher with the provided key.
def initialize_cipher(key):
    return Fernet(key)


# Function to encrypt a  password.
def encrypt_password(cipher, password):
    return cipher.encrypt(password.encode()).decode()


# Function to decrypt a  password.
def decrypt_password(cipher, encrypted_password):
    return cipher.decrypt(encrypted_password.encode()).decode()


# Function to register you.
def register(username, master_password):
    # Encrypt the master password before storing it
    hashed_master_password = hash_password(master_password)
    user_data = {'username': username, 'master_password': hashed_master_password}
    file_name = 'user_data.json'

    if os.path.exists(file_name) and os.path.getsize(file_name) == 0:
        with open(file_name, 'w') as file:
            json.dump(user_data, file)
            print("\n[+] Registration complete!!\n")
    else:
        with open(file_name, 'x') as file:
            json.dump(user_data, file)
            print("\n[+] Registration complete!!\n")


# Function to log you in.
def login(username, entered_password):
    try:
        with open('user_data.json', 'r') as file:
            user_data = json.load(file)

        stored_password_hash = user_data.get('master_password')
        entered_password_hash = hash_password(entered_password)

        if entered_password_hash == stored_password_hash and username == user_data.get('username'):
            print("\n[+] Login Successful..\n")
        else:
            print("\n[-] Invalid Login credentials. Please use the credentials you used to register.\n")
            sys.exit()

    except Exception:
        print("\n[-] You have not registered. Please do that.\n")
        sys.exit()


# Function to view saved websites.
def view_websites():
    try:
        with open('passwords.json', 'r') as data:
            view = json.load(data)
            print("\nWebsites you saved...\n")
            for x in view:
                print(x['website'])
            print('\n')
    except FileNotFoundError:
        print("\n[-] You have not saved any passwords!\n")


# Load or generate the encryption key.
key_filename = 'encryption_key.key'
if os.path.exists(key_filename):
    with open(key_filename, 'rb') as key_file:
        key = key_file.read()
else:
    key = generate_key()
    with open(key_filename, 'wb') as key_file:
        key_file.write(key)

cipher = initialize_cipher(key)


# Function to add (save password).
def add_password(website, password):
    # Check if passwords.json exists
    if not os.path.exists('passwords.json'):
        # If passwords.json doesn't exist, initialize it with an empty list
        data = []
    else:
        # Load existing data from passwords.json
        try:
            with open('passwords.json', 'r') as file:
                data = json.load(file)
        except json.JSONDecodeError:
            # Handle the case where passwords.json is empty or invalid JSON.
            data = []

    # Encrypt the password
    encrypted_password = encrypt_password(cipher, password)

    # Create a dictionary to store the website and password
    password_entry = {'website': website, 'password': encrypted_password}
    data.append(password_entry)

    # Save the updated list back to passwords.json
    with open('passwords.json', 'w') as file:
        json.dump(data, file, indent=4)


# Function to retrieve a saved password.
def get_password(website):
    # Check if passwords.json exists
    if not os.path.exists('passwords.json'):
        return None

    # Load existing data from passwords.json
    try:
        with open('passwords.json', 'r') as file:
            data = json.load(file)
    except json.JSONDecodeError:
        data = []
    # Loop through all the websites and check if the requested website exists.
    for entry in data:
        if entry['website'] == website:
            # Decrypt and return the password
            decrypted_password = decrypt_password(cipher, entry['password'])
            return decrypted_password

    return None


# Infinite loop to keep the program running until the user chooses to quit.
while True:
    print("1. Register")
    print("2. Login")
    print("3. Quit")
    choice = input("Enter your choice: ")

    if choice == '1':  # If a user wants to register
        file = 'user_data.json'
        if os.path.exists(file) and os.path.getsize(file) != 0:
            print("\n[-] Master user already exists!!")
            sys.exit()
        else:
            username = input("Enter your username: ")
            master_password = getpass.getpass("Enter your master password: ")
            register(username, master_password)

    elif choice == '2':  # If a User wants to log in
        file = 'user_data.json'
        if os.path.exists(file):
            username = input("Enter your username: ")
            master_password = getpass.getpass("Enter your master password: ")
            login(username, master_password)
        else:
            print("\n[-] You have not registered. Please do that.\n")
            sys.exit()
        # Various options after a successful Login.
        while True:
            print("1. Add Password")
            print("2. Get Password")
            print("3. View Saved websites")
            print("4. Quit")

            password_choice = input("Enter your choice: ")
            if password_choice == '1':  # If a user wants to add a password
                website = input("Enter website: ")
                password = getpass.getpass("Enter password: ")

                # Encrypt and add the password
                add_password(website, password)
                print("\n[+] Password added!\n")

            elif password_choice == '2':  # If a User wants to retrieve a password
                website = input("Enter website: ")
                decrypted_password = get_password(website)
                if website and decrypted_password:
                    # Copy password to clipboard for convenience
                    pyperclip.copy(decrypted_password)
                    print(f"\n[+] Password for {website}: {decrypted_password}\n[+] Password copied to clipboard.\n")
                else:
                    print("\n[-] Password not found! Did you save the password?"
                          "\n[-] Use option 3 to see the websites you saved.\n")

            elif password_choice == '3':  # If a user wants to view saved websites
                view_websites()

            elif password_choice == '4':  # If a user wants to quit the password manager
                break

    elif choice == '3':  # If a user wants to quit the program
        break

توضیحات:

کتابخونه ها:

json: برای استفاده از فرمت فایل های json(JavaScript Object Notation). از این فرمت برای ذخیره اطلاعات دیکشنری طور و سریالی استفاده میشه.

hashlib: برای استفاده از پروتکل های رمزنگاری امن مثل SHA-256 برای رمزنگاری داده ها با استفاده از یک کلید هست. ما قراره از همین پروتکل استفاده کنیم.

getpass: یک کتابخونه برای وارد کردن امن پسورد(پسورد رو روی صفحه نمایش نمیده). اگر کد رو تست کنید میبینید کاربردش چیه.

os: کتابخونه ای برای ارتباط با سیستم عامل. بیشتر برای کار کردن با فایل ها و فولدر ها.

pyperclip: برای کار کردن با کلیپ‌بورد(جایی که متن های کپی شده ذخیره میشن).

sys: کتابخونه ای که به شما یک سری دسترسی برای کار با سیستم و... میده. جلوتر کاربردش رو میبینید.

cryptography.fernet: بخشی از کتابخونه cryptography. یک سری آپشن برای کد و باز کردن داده ها میده.

تعریف تابع ها:

در گام اول بعد از import کردن کتابخونه ها، تابع hash_password رو برای رمزنگاری پسورد هامون تعریف میکنیم که با استفاده از پروتکل SHA-256 و رمزی که ما در اختیارش قرار دادیم رمزنگاری میکنه.

چهار تا تابع بعدی برای رمزنگاری Fernet هستن. این مدل توضیحات زیادی داره اما میتویند اینجا راجع بهش بخونید. استفاده از Fernet برای افزایش امنیت برناممون هست و علاوه بر رمزنگاری اصلی، یک لایه دیگه امنیتی هم اضافه میکنه که این باعث میشه به احتمال ۹۹.۹۹ درصد رمز های شما لو نره(البته از طرف پسورد منیجر!).

پسوورد منیجر ما قابلیت داشتن چند کاربر مختلف داره و میتونیم چند یوزر مختلف با ست پسوورد های مختلف داشته باشیم. تابع register برای ساخت یوزر جدید و ذخیره اطلاعات اون توی user_data.json هست. پسوورد اصلی مون هم رمزنگاری میکنیم و توی همین فایل ذخیره میکنیم.

تابع بعدی login هست. این تابع برای اینه که یوزر و پسوردی که ما وارد میکنیم چک کنه و ببینه آیا درسته یا نه؟ اگر درست بود پسورد هامون رو بهمون بده و اگر غلط بود هم قبول نکنه.

تابع view_websites تابعی هست که اسم تمام سایت هایی که ما پسوردی رو برای اونها ذخیره کردیم بهمون میده.

خط های بعدی تا سر تابع add_password برای این هست که ما کلید Fernet رو یا بسازیم و یا اگر وجود داره لودش کنیم.

خود تابع add_password هم یک پسوورد رو میگیره، رمزنگاری میکنه و در فایل json ما ذخیره میکنه.

تابع get_password سعی میکنه با کلیدی که بهش ارائه دادیم فایل json رو باز کنه، عبارت رمزنگاری شده رو باز کنه و رمزی که ذخیره کرده بودیم رو به ما تحویل بده.

حلقه اصلی:

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

خب کد تموم شد. حتما امتحانش کنید چون خیلی میتونه مفید باشه(خودم استفاده میکنم) و اگر بخواید واقعا رمز هاتون ۱۰۰ درصد امن باشه و به هیچ عنوان قابل دسترسی نباشه(اگر رمز اصلیتون قوی باشه) این ابزار میتونه خیلی مفید باشه.

میتونید این پسورد منیجر رو پیشرفت هم بدید. مثلا آنلاینش کنید(امنیتش پایین تر میاد البته نه خیلی) یا رابط گرافیکی براش طراحی کنید.

امیدوارم براتون مفید بوده باشه D:


  • چقدر من همچین چیزیو لازم داشتم واقعا اونم با توضیحات دقیق و فوق العاده شما
    وبلاگ خوبتونو به بقیه دوستانم هم معرفی کردم
    واقعا زحمت می کشیدممنونم
    پاسخ:
    سلام دوست عزیز.
    خوشحالم که این پست براتون مفید بوده.
    خیلی ممنونم از لطف و همراهی شما.
    موفق باشید.
ارسال نظر آزاد است، اما اگر قبلا در بیان ثبت نام کرده اید می توانید ابتدا وارد شوید.
شما میتوانید از این تگهای html استفاده کنید:
<b> یا <strong>، <em> یا <i>، <u>، <strike> یا <s>، <sup>، <sub>، <blockquote>، <code>، <pre>، <hr>، <br>، <p>، <a href="" title="">، <span style="">، <div align="">
تجدید کد امنیتی