في هذه المدونة اثنتا عشرة مقالة تشرح كيف ينبغي أن تُفعل الأشياء: أن الطول أهم من الرموز، وأن مدير كلمات المرور ليس رفاهية بل الطريقة الوحيدة لتنفيذ القاعدة، وأن النسبة المئوية لا تقول شيئًا.
كتابة ذلك سهلة. المزعج هو أن تنظر إلى موقعك أنت بالمسطرة نفسها. فعلنا ذلك، وكانت هناك ثلاثة أشياء خطأ. ها هي كاملة، مع الأرقام التي فضحتها، لأن موقعًا أمنيًا لا ينشر إلا إصاباته يساوي أقل بكثير.
كان الفاحص يتجمّد بينما تكتب
يحلّل الفاحص كلمة مرورك بواسطة zxcvbn، وهي مكتبة تبحث عن الأنماط بدل عدّ الأحرف الكبيرة. تعمل جيدًا جدًا ولها ثمن: تُنفَّذ كاملة، دفعة واحدة، على الخيط نفسه الذي يرسم الصفحة. وما دامت تعمل، لا يستطيع المتصفح فعل أي شيء آخر.
هذا الثمن يكبر بسرعة مع الطول. قِيس بالحزمة نفسها التي يقدّمها الموقع، وبكلمات مرور
من النوع الذي يكتبه الناس فعلًا — كلمات وسنوات و@ بدل a:
| الطول | تنفيذ واحد |
|---|---|
| 16 محرفًا | 45 ms |
| 20 محرفًا | 121 ms |
| 32 محرفًا | 273 ms |
| 64 محرفًا | 843 ms |
| 128 محرفًا | 3٬621 ms |
إلى هنا، طبيعي. المشكلة كانت في عدد المرات التي كنا نطلقها فيها.
كان الحقل موصولًا بمستمعَين اثنين مختلفين، input وkeyup. والمفتاح العادي
يُطلق كليهما. فمع كل حرف تضغطه كان التحليل الكامل يجري مرتين: 90 ms في كلمة مرور
من 16 محرفًا، ونصف ثانية في واحدة من 32.
ولم يكن هناك ما يكبحه: لا مؤقّت، ولا حدّ للطول، ولا خيط منفصل. ابتداءً من نحو عشرين محرفًا صار المتصفح يستغرق في التحليل أكثر مما تستغرقه أنت للضغط على المفتاح التالي. كانت الضغطات تتراكم في طابور لم يعد يفرغ أبدًا، وكانت الصفحة تتوقف عن الاستجابة بينما تكتب. ولصق كلمة مرور طويلة كان يجمّدها عدة ثوانٍ.
الإصلاح تغييران صغيران. أزلنا مستمع keyup، لأن input يغطي أصلًا الكتابة واللصق
والحذف والتعبئة التلقائية من المدير: يختفي نصف العمل دون أن يتغير أي شيء مما تراه.
وأضفنا انتظارًا مقداره 150 جزءًا من الألف من الثانية: ما دمت تكتب لا يُحلَّل شيء،
ويُحلَّل فور توقفك. ولا أحد يكتب ببطء يكفي ليلاحظ ذلك.
النتيجة مطابقة. لا يزال Barcelona1992$ يقول الشيء نفسه: إن «barcelona» في القاموس،
وإن 1992 تبدو سنة، وإنها تسقط في أقل من ثانية.
كان الوصف مبتورًا في منتصف الجملة في خمس عشرة لغة
هذه أسخف وأكثر إحراجًا.
الجملة التي تظهر تحت العنوان في محرك البحث — وصف الميتا — كانت مبتورة في خمس عشرة من لغات الفاحص الثماني عشرة. لم تسلم إلا الإسبانية والكورية واليابانية. قصّها أحدهم في وقت ما بحجة الطول، وقطع في منتصف الكلمة، ولم ينظر أحد بعدها.
وفي ثلاث لغات وقع القطع في منتصف محرف خاص تمامًا، فكان ما ننشره في غوغل هو هذا:
| اللغة | ما كنا نقدّمه | ما كان ينبغي أن يقوله |
|---|---|---|
| البرتغالية | …datas e padr&o |
padrões |
| التركية | …arıyor ve ger&cced |
gerçekten |
| الفيتنامية | …chúng tôi tra mật kh&# |
mật khẩu |
اللافت هو موضعه: في الصفحة الأفضل أداءً في الموقع كله. فالفاحص يحوّل أفضل بكثير من المولّد، وكان يفعل ذلك بوصف مكسور. الخمس عشرة مكتملة الآن.
وبالمناسبة، في الكورية واليابانية والفيتنامية انتقلت العلامة من أول العنوان إلى آخره. ففي نتائج البحث يظهر النطاق منفصلًا أصلًا، والبدء بـ«password.es ·» لم يكن إلا إهدارًا للمساحة الأثمن.
انحياز بمقدار واحد في مئة مليون
يختار المولّد كل محرف بـcrypto.getRandomValues()، وهو مصدر العشوائية الجيد في
المتصفح. لكن لتحويل ذلك العدد الهائل إلى «موضع في الأبجدية» كنا نستخدم باقي القسمة،
وهناك فخّ كلاسيكي: 2³² ليس من مضاعفات 83، ولذلك كانت المواضع الأولى من الأبجدية
تخرج أكثر بقليل جدًا من الأخيرة.
كم هو «بقليل جدًا»: مع أبجدية تصل إلى 89 محرفًا، من رتبة جزء في مئة مليون. لا يغيّر شيئًا. ولا يجعل كلمة مرورك أضعف بقدر يمكن قياسه، ولا يقترب من ذلك.
أصلحناه على أي حال، وهو ثلاثة أسطر: تُستبعَد القيم الـ45 الزائدة من أصل 4٬294٬967٬296 قيمة ممكنة ويُعاد السحب. في موقع عن كلمات المرور، «إنه مهمَل» ليس سببًا وجيهًا لترك انحياز حين تكون كلفة إزالته بهذا القدر.
ما كان ناقصًا: أن يفرض المتصفح الوعد
لدينا مقالة كاملة تشرح أن كلمة مرورك لا تخرج من هنا. كان ذلك صحيحًا، ومع ذلك لم يكن سوى جملة منّا: لم يكن هناك ما يمنع تقنيًا نصًا برمجيًا محقونًا من أن يفعل شيئًا آخر.
الآن تحمل كل صفحة سياسة أمان محتوى. الجزءان اللذان يهمّان:
- لا يُنفَّذ أي نص برمجي لم يكن في الصفحة وقت بنائها. كل نص شرعي موقّع ببصمته؛ والمحقون لا يطابق، فيرفض المتصفح تشغيله.
connect-src 'none'. الموقع لا يُجري ولا طلب شبكة واحدًا من جافاسكربت، وصار المتصفح هو من يفرض ذلك. ولو حاول شيء يومًا أن يرسل ما تكتبه إلى مكان ما، فلن يخرج.
كفّ الوعد عن كونه تصريحًا وصار قاعدة.
ما لا يزال خطأً
تحديث 31 أغسطس. الأمور الثلاثة في هذا القسم صُحّحت في اليوم نفسه الذي نُشر فيه هذا المقال: صارت اللغات الخمس عشرة تصف المحرك الحقيقي، وصار المقياسان مقياسًا واحدًا، وأسئلة الفاحص الشائعة تشرح مسألة الرموز. وتبقى مكتوبة مع ذلك، لأن سجل ما كان خطأً أثمن من صورة موقع بلا عيب.
هنا تكسب هذه المقالة مكانها.
خمس عشرة لغة ما زالت تصف الفاحص بأنه المحرك القديم. يقول نصّ تلك الصفحات إنه
يعيد إنتاج منطق PasswordMeter الكلاسيكي. لم يعد كذلك: استُبدل ذلك المحرك لأنه كان
يمنح Password1! تقدير «قوية جدًا» ويُرسِب عبارة من خمس كلمات، أي عكس ما ينبغي قوله
تمامًا. الإسبانية والكورية واليابانية محدَّثة؛ والخمس عشرة الأخرى لا.
هناك مقياسان مختلفان في البيت نفسه. الصفحة الرئيسية تقرّر قوة كلمة المرور من بتّاتها؛ والفاحص يقرّرها من الزمن اللازم لكسرها. معياران مختلفان، ولا ننبّه إلى ذلك في أي موضع.
المولّد والفاحص لا يعدّان الرموز نفسها: أحدهما يستخدم 27، والآخر يفترض 33. الفارق صغير، لكنه موجود.
لا واحد من الثلاثة خطير. الثلاثة دَين، وهي تفضّل أن تكون مكتوبة هنا على أن تنتظر من يجدها.
سجلّ هذه النسخة
بما أن المستودع ليس عامًا، فسجلّ التغييرات هنا كاملًا. النسخة 0.2.0، في 31 أغسطس 2026:
أُضيف. سياسة أمان محتوى لكل صفحة، ببصمة كل نص برمجي. المقالة عن مكان كلمات مرورك المحفوظة، في اللغات الثماني عشرة. وطابور تحريري يقرّر ما يُكتب، ويأمر بألا يُنشر شيء إذا فرغ.
أُصلح. وصف الفاحص، المبتور في منتصف الجملة في خمس عشرة لغة، ثلاث منها بمحرف مشطور نصفين. وتجمّد اللسان أثناء الكتابة. وانحياز القرعة. والصورة الناقصة في المقالة السابقة.
تغيّر. عنوان الفاحص بالكورية واليابانية والفيتنامية. والنشر، الذي صار ينطلق حين يكون الموقع المبني موجودًا فعلًا لا قبل ذلك بدقيقة. والترجمات إلى الفيتنامية والهندية والعربية، التي لم تعد تعطّل نشرًا وإن بقيت الأضعف.
أرقام هذه المقالة مقيسة لا مقدَّرة: أزمنة zxcvbn بالحزمة نفسها التي يقدّمها الموقع وبكلمات مرور تتضمن كلمات واستبدالات؛ وانحياز القرعة محسوب على قيم عدد صحيح من 32 بت البالغة 4٬294٬967٬296. ومحرك الفاحص هو zxcvbn مفتوح المصدر.
صورة بواسطة Ernandes Alves · Pexels