ساخت ژنراتور پسورد امن با HTML، CSS و جاوا اسکریپت

آموزش کامل ساخت ابزار تولید رمز عبور پیشرفته و ارزیاب قدرت پسورد در مرورگر با یک فایل مستقل و بدون نیاز به افزونه یا سرور خارجی.

🎧 خلاصه صوتی مقاله (پادکست ۲ دقیقه‌ای):

فرصت مطالعه ندارید؟ چکیده این مطلب را همین‌جا گوش دهید:

امنیت حساب‌های کاربری در فضای دیجیتال بیش از هر زمان دیگری به استحکام رمزهای عبور وابسته است. استفاده از کلمات قابل حدس یا تاریخ تولد، درگاه را برای حملات سایبری باز می‌گذارد. در این مقاله قصد داریم با هم یک ابزار کاملاً کاربردی و مدرن برای «تولید رمز عبور امن» و «سنجش قدرت پسورد» بسازیم که کل فرآیند تولید و پردازش آن به‌صورت محلی (Client-Side) درون مرورگر اجرا می‌شود. زیبایی این پروژه در این است که نیازی به هیچ کتابخانه سنگین خارجی، سرور یا افزونه‌ای ندارد و تمام منطق آن در قالب یک فایل واحد HTML پیاده‌سازی می‌شود.

اگر به مباحث امنیت وب علاقه دارید یا می‌خواهید فراتر از ابزارهای معمولی کار کنید، پیشنهاد می‌کنیم نگاهی به مقاله معرفی Hackingtool؛ جعبه‌ابزار جامع و متن‌باز امنیت سایبری با هوش مصنوعی بیندازید تا با ابزارهای حرفه‌ای‌تر این حوزه نیز آشنا شوید. حالا بیایید دست به آچار شویم و کد کامل این ابزار جذاب را بنویسیم.

ساختار کلی و فلسفه طراحی ابزار

برای ساخت یک ژنراتور پسورد استانداردی که هم زیبا باشد و هم تجربه کاربری فوق‌العاده‌ای ارائه دهد، سه بخش اصلی را در نظر می‌گیریم:

  • بخش نمایش و کپی: فضایی برای نمایش پسورد تولید شده و یک دکمه‌ی کپی سریع به همراه پیام تأیید بصری (Toast).
  • تنظیمات سفارشی‌سازی: اسلایدر تعیین طول پسورد (از ۸ تا ۶۴ کاراکتر) و چک‌باکس‌های انتخاب مجموعه کاراکترها (حروف بزرگ، حروف کوچک، اعداد و نمادهای خاص).
  • نوار ارزیاب امنیت: الگوریتمی که آنی تعداد کاراکترها و تنوع آن‌ها را می‌سنجد و با یک نوار رنگی پویا، میزان قدرت پسورد را از ضعیف تا بسیار قوی نمایش می‌دهد.
ویژگیمقدار / توضیحات
زبان‌های استفاده شدهHTML5, CSS3, Vanilla JavaScript
ساختار فایلتک‌فایلی (Single-file) بدون نیاز به وابستگی
پردازش داده‌ها۱۰۰٪ محلی در مرورگر (Local Browser Execution)
وضعیت دسترسی ایرانکاملاً در دسترس (بدون محدودیت)

کد کامل و یکپارچه‌ پروژه

کد زیر را کپی کرده و در یک فایل متنی با نام دلخواه مثلاً password-generator.html ذخیره کنید. سپس با هر مرورگری آن را باز کنید تا ابزار آماده به کار باشد.

<!DOCTYPE html>
<html lang="fa" dir="rtl">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>ژنراتور پیشرفته رمز عبور امن</title>
    <style>
        :root {
            --bg-color: #0f172a;
            --card-bg: #1e293b;
            --text-color: #f8fafc;
            --accent-color: #38bdf8;
            --accent-hover: #0ea5e9;
            --border-color: #334155;
            --danger: #ef4444;
            --warning: #f59e0b;
            --success: #22c55e;
        }
        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
            font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
        }
        body {
            background-color: var(--bg-color);
            color: var(--text-color);
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
            padding: 20px;
        }
        .container {
            background-color: var(--card-bg);
            border: 1px solid var(--border-color);
            border-radius: 16px;
            padding: 30px;
            width: 100%;
            max-width: 450px;
            box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3);
        }
        h1 {
            font-size: 1.25rem;
            margin-bottom: 20px;
            text-align: center;
            color: var(--accent-color);
        }
        .result-box {
            position: relative;
            background: var(--bg-color);
            border: 1px solid var(--border-color);
            border-radius: 10px;
            padding: 15px;
            display: flex;
            align-items: center;
            justify-content: space-between;
            margin-bottom: 20px;
        }
        .result-box input {
            background: transparent;
            border: none;
            color: var(--text-color);
            font-size: 1.2rem;
            width: 100%;
            outline: none;
            font-family: monospace;
            letter-spacing: 1px;
        }
        .copy-btn {
            background: var(--accent-color);
            border: none;
            border-radius: 8px;
            color: var(--bg-color);
            cursor: pointer;
            padding: 8px 12px;
            font-weight: bold;
            transition: background 0.2s;
        }
        .copy-btn:hover {
            background: var(--accent-hover);
        }
        .strength-meter {
            height: 6px;
            width: 100%;
            background: var(--border-color);
            border-radius: 3px;
            margin-bottom: 20px;
            overflow: hidden;
        }
        .strength-bar {
            height: 100%;
            width: 0%;
            transition: width 0.3s, background-color 0.3s;
        }
        .settings {
            display: flex;
            flex-direction: column;
            gap: 15px;
            margin-bottom: 25px;
        }
        .setting-group {
            display: flex;
            justify-content: space-between;
            align-items: center;
        }
        .setting-group label {
            font-size: 0.95rem;
            color: #cbd5e1;
        }
        .setting-group input[type="range"] {
            flex: 1;
            margin-right: 15px;
            accent-color: var(--accent-color);
        }
        .setting-group input[type="checkbox"] {
            width: 18px;
            height: 18px;
            accent-color: var(--accent-color);
            cursor: pointer;
        }
        .generate-btn {
            width: 100%;
            background: var(--accent-color);
            border: none;
            border-radius: 10px;
            color: var(--bg-color);
            font-size: 1rem;
            font-weight: bold;
            padding: 12px;
            cursor: pointer;
            transition: background 0.2s;
        }
        .generate-btn:hover {
            background: var(--accent-hover);
        }
        .toast {
            position: fixed;
            bottom: 20px;
            background: var(--success);
            color: #fff;
            padding: 10px 20px;
            border-radius: 8px;
            font-size: 0.9rem;
            opacity: 0;
            transition: opacity 0.3s ease;
            pointer-events: none;
        }
        .toast.show {
            opacity: 1;
        }
    </style>
</head>
<body>

    <div class="container">
        <h1>ژنراتور امن رمز عبور</h1>
        
        <div class="result-box">
            <input type="text" id="passwordDisplay" readonly>
            <button class="copy-btn" id="copyBtn">کپی</button>
        </div>

        <div class="strength-meter">
            <div class="strength-bar" id="strengthBar"></div>
        </div>

        <div class="settings">
            <div class="setting-group">
                <label for="lengthRange">طول پسورد: <span id="lengthVal">16</span></label>
                <input type="range" id="lengthRange" min="8" max="64" value="16">
            </div>
            <div class="setting-group">
                <label for="includeUppercase">حروف بزرگ (A-Z)</label>
                <input type="checkbox" id="includeUppercase" checked>
            </div>
            <div class="setting-group">
                <label for="includeLowercase">حروف کوچک (a-z)</label>
                <input type="checkbox" id="includeLowercase" checked>
            </div>
            <div class="setting-group">
                <label for="includeNumbers">اعداد (0-9)</label>
                <input type="checkbox" id="includeNumbers" checked>
            </div>
            <div class="setting-group">
                <label for="includeSymbols">نمادهای خاص (!@#$)</label>
                <input type="checkbox" id="includeSymbols" checked>
            </div>
        </div>

        <button class="generate-btn" id="generateBtn">ساخت رمز جدید</button>
    </div>

    <div class="toast" id="toast">رمز عبور با موفقیت کپی شد!</div>

    <script>
        const uppercaseChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
        const lowercaseChars = 'abcdefghijklmnopqrstuvwxyz';
        const numberChars = '0123456789';
        const symbolChars = '!@#$%^&*()_+-=[]{}|;:,.<>?';

        const passwordDisplay = document.getElementById('passwordDisplay');
        const lengthRange = document.getElementById('lengthRange');
        const lengthVal = document.getElementById('lengthVal');
        const includeUppercase = document.getElementById('includeUppercase');
        const includeLowercase = document.getElementById('includeLowercase');
        const includeNumbers = document.getElementById('includeNumbers');
        const includeSymbols = document.getElementById('includeSymbols');
        const generateBtn = document.getElementById('generateBtn');
        const copyBtn = document.getElementById('copyBtn');
        const strengthBar = document.getElementById('strengthBar');
        const toast = document.getElementById('toast');

        // به‌روزرسانی مقدار نمایشی طول پسورد
        lengthRange.addEventListener('input', () => {
            lengthVal.textContent = lengthRange.value;
            generatePassword();
        });

        function generatePassword() {
            let chars = '';
            if (includeUppercase.checked) chars += uppercaseChars;
            if (includeLowercase.checked) chars += lowercaseChars;
            if (includeNumbers.checked) chars += numberChars;
            if (includeSymbols.checked) chars += symbolChars;

            if (chars === '') {
                passwordDisplay.value = 'حداقل یک گزینه را انتخاب کنید!';
                strengthBar.style.width = '0%';
                return;
            }

            let password = '';
            for (let i = 0; i < lengthRange.value; i++) {
                const randomIndex = Math.floor(Math.random() * chars.length);
                password += chars[randomIndex];
            }

            passwordDisplay.value = password;
            evaluateStrength(password);
        }

        function evaluateStrength(pwd) {
            let score = 0;
            if (pwd.length > 11) score += 1;
            if (pwd.length > 19) score += 1;
            if (/[A-Z]/.test(pwd)) score += 1;
            if (/[0-9]/.test(pwd)) score += 1;
            if (/[^A-Za-z0-9]/.test(pwd)) score += 1;

            let percentage = (score / 5) * 100;
            strengthBar.style.width = percentage + '%';

            if (score <= 2) {
                strengthBar.style.backgroundColor = 'var(--danger)';
            } else if (score === 3 || score === 4) {
                strengthBar.style.backgroundColor = 'var(--warning)';
            } else {
                strengthBar.style.backgroundColor = 'var(--success)';
            }
        }

        copyBtn.addEventListener('click', () => {
            if (!passwordDisplay.value || passwordDisplay.value.includes('انتخاب کنید')) return;
            navigator.clipboard.writeText(passwordDisplay.value);
            toast.classList.add('show');
            setTimeout(() => {
                toast.classList.remove('show');
            }, 2000);
        });

        generateBtn.addEventListener('click', generatePassword);

        // اجرای اولیه هنگام لود صفحه
        generatePassword();
    </script>
</body>
</html>

تحلیل بخش‌به‌بخش ساختار کد

برای اینکه درک درستی از نحوه‌ی کارکرد این اسکریپت داشته باشید، بخش‌های مهم کدهای بالا را بررسی می‌کنیم:

  • رابط کاربری مدرن با CSS متغیرها: از رنگ‌های تیره (Dark Mode) و پالت‌های استاندارد طراحی استفاده شده تا هم چشم کاربر خسته نشود و هم ظاهر ابزار حرفه‌ای به نظر برسد.
  • رشته‌های کاراکتری (Character Pools): متغیرهایی مانند uppercaseChars و symbolChars تمامی کاراکترهای مجاز را در خود جای داده‌اند. اسکریپت با توجه به وضعیت چک‌باکس‌ها، این مجموعه‌ها را با هم ترکیب می‌کند.
  • حلقه تولید تصادفی: تابع generatePassword با استفاده از تابع ریاضی Math.random() و به تعداد طول مشخص‌شده در اسلایدر، کاراکترها را به صورت تصادفی انتخاب و به هم متصل می‌کند.
  • ارزیابی هوشمند امنیت: تابع evaluateStrength بررسی می‌کند که آیا پسورد طول کافی دارد یا خیر و آیا از انواع حروف، اعداد و نمادها در آن استفاده شده است یا نه. بر اساس این امتیاز، عرض و رنگ نوار تغییر می‌کند.
  • کپی کلیپ‌بورد با بازخورد (Toast): با استفاده از رابط برنامه‌نویسی مدرن مرورگر یعنی navigator.clipboard، پسورد با یک کلیک کپی می‌شود و پیام کوچکی در پایین صفحه ظاهر می‌شود تا کاربر از انجام عملیات مطمئن شود.

نکات کلیدی برای ارتقاء و سفارشی‌سازی پروژه

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

یکی از اشتباهات رایج توسعه‌دهندگان مبتدی در ساخت ژنراتورهای پسورد، استفاده از توابع تولید عدد تصادفی ضعیف برای اهداف رمزنگاری حساس است. برای پروژه‌های سطح سازمانی یا کیف پول‌های دیجیتال، استفاده از شیء استاندارد رمزنگاری مرورگر یعنی window.crypto.getRandomValues() پیشنهاد می‌شود؛ هرچند برای کاربردهای عمومی وب، روش به‌کاررفته در این مقاله کاملاً سریع و کارآمد است.

پرسش‌های متداول

آیا این ابزار نیاز به اتصال اینترنت دارد؟

خیر. به محض اینکه فایل HTML را در مرورگر خود باز کنید، تمام پردازش‌ها درون سیستم خودتان انجام می‌شود و هیچ اطلاعاتی به هیچ سروری ارسال نمی‌شود.

چگونه می‌توانم حداکثر طول پسورد را افزایش دهم؟

در کد HTML، در تگ مربوط به اسلایدر طول پسورد، ویژگی max="64" قرار دارد. شما می‌توانید این عدد را به مقدار دلخواه مثل 128 تغییر دهید.

چرا دکمه کپی پیام خطا می‌دهد یا کار نمی‌کند؟

برخی مرورگرها دسترسی به کلیپ‌بورد را نیازمند بستر امن (HTTPS یا فایل لوکال با پروتکل‌های استاندارد) می‌دانند. مطمئن شوید که فایل را به صورت مستقیم در یک مرورگر مدرن باز کرده‌اید.

جمع‌بندی

در این آموزش یاد گرفتیم که چگونه با نوشتن تنها یک فایل شامل کدهای تمیز HTML، CSS و جاوا اسکریپت، یک ژنراتور پسورد امن و ارزیاب قدرت رمز عبور حرفه‌ای بسازیم. این ابزار نه تنها به امنیت دیجیتال شخصی شما کمک می‌کند، بلکه تمرین بسیار خوبی برای درک تعاملات DOM و مدیریت رویدادها در جاوا اسکریپت است. پیشنهاد می‌کنیم کد را تغییر دهید، استایل آن را شخصی‌سازی کنید و آن را به عنوان یک ابزار دم دست همیشه همراه داشته باشید.

پاسخی بگذارید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *