برمجة

مولّد كلمات المرور بـ JavaScript: درس

جرّب الأداة الجاهزة: مولّد كلمات المرور ←

أداة مباشرة

مولّد كلمات المرور (crypto)

يعمل في المتصفح ولا يُرسل شيء إلى خادم.

ما هو JavaScript Password Generator؟

مولّد كلمات المرور يأخذ أحرفاً عشوائية من المجموعة التي تختارها ويرصّها. السؤال الأساسي: من أين تأتي العشوائية؟ في المتصفح طريقان. Math.random سريع لكنه ليس لكلمات المرور لأن ناتجه قابل للتوقع. أما crypto.getRandomValues فيعطي بايتات من المصدر التشفيري لنظام التشغيل. لكلمات المرور يُستعمل الثاني فقط. كل شيء يحدث داخل الصفحة ولا يذهب شيء إلى خادم.

فيمَ يُستخدم JavaScript Password Generator؟

هذا الدرس يجمع الأرقام العشوائية الآمنة والنموذج والنسخ في JavaScript.

  • الحصول على كلمة مرور قوية لحساب جديد
  • سلسلة طويلة لشبكة Wi-Fi أو مفتاح API
  • تعلّم الفرق بين Math.random وcrypto
  • زر نسخ بـ Clipboard API

ماذا يمكن فعله باستخدام JavaScript Password Generator؟

يختار المستخدم الطول (مثلاً 8–64) والمجموعات: أحرف صغيرة وكبيرة وأرقام ورموز. الكود يجمع المجموعات المختارة في سلسلة واحدة. ثم يأخذ فهرساً عشوائياً لكل حرف. كلمة المرور الجاهزة تُنسخ بزر واحد. على HTTPS يعطي المتصفح navigator.clipboard، وإلا يبقى طريق execCommand القديم. لا تُكتب كلمة المرور في localStorage ولا تُرسل لأي مكان. لتجربة الأداة الكاملة افتح /tools/password.

هل تعلم JavaScript Password Generator صعب؟

الكود قصير لكن فيه فخ. إذا أخذت البايت العشوائي «% الطول» فقط، تظهر بعض الأحرف أكثر من غيرها. هذا يسمى انحياز modulo. الحل rejection sampling: ترمي الرقم الذي يتجاوز أكبر حد يقبل القسمة على طول المجموعة وتأخذ رقماً جديداً. وأيضاً: إذا أردت حرفاً واحداً على الأقل من كل مجموعة فعليك الخلط بعدها، والخلط يجب أن يستعمل crypto.

المزايا والحدود

الميزة: لا خادم ولا أثر والكود يعمل في كل متصفح. الحد: حفظ كلمة المرور مسؤوليتك — استعمل مدير كلمات مرور. الطول يعطي قوة أكثر من أنواع الأحرف.

أفكار أساسية

إذا عرفت هذه الأفكار الأربع صار كل سطر في الكود واضحاً.

  • crypto.getRandomValues — عشوائية تشفيرية
  • Math.random — للألعاب لا لكلمات المرور
  • Rejection sampling — ضد انحياز modulo
  • الإنتروبيا ≈ الطول × log2(حجم المجموعة)

مثال قصير

دالة تأخذ فهرساً عشوائياً بلا انحياز، والحلقة التي تبني كلمة المرور:

1. فهرس عشوائي بلا انحياز:

function randomIndex(max) {
  const limit = Math.floor(0x100000000 / max) * max;
  const buf = new Uint32Array(1);
  do { crypto.getRandomValues(buf); } while (buf[0] >= limit);
  return buf[0] % max;
}

هذه الدالة تعيد فهرساً عشوائياً من 0 إلى max-1.

limit هو أكبر عدد أقل من 2^32 يقبل القسمة على max.

crypto.getRandomValues يكتب عدداً عشوائياً تشفيرياً في buf.

إذا كان العدد أكبر من limit أو يساويه يُرمى ويؤخذ غيره. هكذا لا يظهر فهرس أكثر من غيره.

في النهاية % max يضع العدد بين 0 و max-1.

2. مجموعات الأحرف:

const SETS = {
  lower: "abcdefghijklmnopqrstuvwxyz",
  upper: "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
  digits: "0123456789",
  symbols: "!@#$%^&*()-_=+[]{};:,.?",
};

هذا الكائن يحفظ أربع مجموعات: أحرف صغيرة، كبيرة، أرقام، رموز.

ما يختاره المستخدم بمربعات الاختيار هو فقط ما تُؤخذ منه كلمة المرور.

كلما كبرت المجموعة زادت خيارات كل حرف وصعب تخمين كلمة المرور.

3. الحلقة التي تبني كلمة المرور:

function makePassword(length, chosen) {
  const pool = chosen.map((k) => SETS[k]).join("");
  if (!pool) throw new Error("Choose at least one set");
  let out = "";
  for (let i = 0; i < length; i++) out += pool[randomIndex(pool.length)];
  return out;
}

chosen هي أسماء المجموعات المختارة، مثل ["lower", "digits"]. pool يجمع أحرفها في نص واحد.

إذا لم يُختر شيء ترمي الدالة خطأ بدل إعادة كلمة مرور فارغة.

الحلقة تعمل length مرة. في كل مرة يختار randomIndex حرفاً من المجموعة ويضيفه إلى نهاية out.

النتيجة: نص كلمة المرور الجاهز الذي يظهر على الشاشة، مثل k7#Qm2…

4. حرف واحد على الأقل من كل مجموعة ثم الخلط:

function makeStrongPassword(length, chosen) {
  const chars = chosen.map((k) => SETS[k][randomIndex(SETS[k].length)]);
  const pool = chosen.map((k) => SETS[k]).join("");
  while (chars.length < length) chars.push(pool[randomIndex(pool.length)]);
  for (let i = chars.length - 1; i > 0; i--) {
    const j = randomIndex(i + 1);
    [chars[i], chars[j]] = [chars[j], chars[i]];
  }
  return chars.join("");
}

السطر الأول يأخذ حرفاً إلزامياً من كل مجموعة مختارة. فإذا اختيرت الأرقام فستحتوي كلمة المرور رقماً دائماً.

while يملأ الأماكن الباقية من المجموعة المشتركة.

حلقة for هي خلط Fisher–Yates: تبدّل الأماكن عشوائياً كي لا تبقى الأحرف الإلزامية في البداية دائماً.

النتيجة: كلمة مرور فيها كل نوع مختار، بترتيب لا يمكن تخمينه.

أسئلة شائعة

  • هل أستعمل Math.random؟ ليس لكلمات المرور. ناتجه ليس تشفيرياً ويمكن توقعه.
  • هل تُرسل كلمة المرور إلى خادم؟ لا. تُحسب في المتصفح ولا تُحفظ في أي مكان.
  • كم حرفاً يكفي؟ 16 على الأقل. الطول يساعد أكثر من أنواع الأحرف.
  • أين الأداة الجاهزة؟ في nibrascode.com/tools/password.