العربية

التشفير والهروب والتجزئة

Base64 ليس تشفيرًا، وbtoa ليس UTF-8، وencodeURI ليس encodeURIComponent، وSHA-256 ليس تجزئة كلمة المرور. وإليكم ما يفعله كل واحد من هؤلاء في الواقع، والأخطاء المحددة التي تتبع افتراض خلاف ذلك.

التشفير ليس تشفيرًا، وليس ضغطًا

يغير التشفير كيفية كتابة البيانات. يغير التشفير من يمكنه قراءته. يغير الضغط مقدار المساحة التي يستغرقها. هذه ثلاث وظائف مختلفة، وbase64 يقوم بالمهمة الأولى فقط - بشكل سيئ، إذا كنت تأمل في أي من الوظيفتين الأخريين.

يأخذ Base64 ثلاث بايتات في كل مرة ويعيد كتابتها كأربعة أحرف مأخوذة من أبجدية رمز 64. أربعة أحرف تحمل ثلاثة بايتات تعني أن الإخراج يكون دائمًا أكبر بنحو 33% من الإدخال، بالإضافة إلى المساحة المتروكة. إنه موجود لأن قدرًا كبيرًا من البنية التحتية - رؤوس البريد الإلكتروني، HTTP الرؤوس، JSON قيم السلسلة، عناوين URL، XML السمات - تم تصميمها للنص والتشويه أو رفض البايتات العشوائية. Base64 هو المحول الذي يتيح لك دفع البايتات عبر أنبوب على شكل نص.

يمكن لأي شخص عكس ذلك على الفور، بدون مفتاح، لأنه لا يوجد مفتاح. إذا قمت بإنشاء كلمة مرور، فقد قمت بنشر كلمة المرور بتنسيق غير مناسب إلى حد ما. وهذا مهم لأن مخرجات Base64 تبدو مشوشة للعين البشرية، وهي بالضبط الخاصية التي تجعل الناس يثقون بها في الأشياء التي لا يمكنها القيام بها.

لماذا ينكسر btoa()، والطريقتان المختلفتان لكسره

يمنحك المتصفح btoa() و atob()، وهما أقدم من واجهات برمجة التطبيقات النصية الحديثة. يتم تعريف btoa عبر "سلاسل ثنائية": سلاسل تكون فيها كل وحدة تعليمات برمجية عبارة عن بايت واحد، من 0 إلى 255. النص ليس ذلك.

الفشل الأول بصوت عال. اتصل بـ btoa("世界") وستحصل على خطأ InvalidCharacterError، لأن U+4E16 لا يتناسب مع البايت. تعتبر حالات الفشل الصاخبة من النوع الجيد، حيث تلاحظها على الفور وتبحث عن حل لها.

أما الفشل الثاني فيصمت وهو الذي يصل إلى الإنتاج. الحرف é هو U+00E9، والذي يتناسب مع البايت. لذلك يعود btoa("café") بسعادة، مع ترميز é باعتباره البايت المفرد 0xE9. ولكن é في UTF-8 هو بايتان، 0xC3 0xA9. يقوم Base64 الذي أنتجته للتو بفك التشفير، في كل نظام آخر على وجه الأرض، لشيء ليس نصك. ستكتشف بعد أسابيع متى تحول اسم في قاعدة البيانات إلى حرف بديل.

الحل هو التوقف عن التعامل مع النص كبايت وتحويله بشكل صريح. يقوم TextEncoder بإنتاج UTF-8 بايت؛ تشفير تلك. يقوم TextDecoder بتحويل البايتات مرة أخرى إلى نص، وإنشاءها باستخدام { Fatal: true } يجعلها ترمي على تسلسلات غير صالحة بدلاً من استبدال U+FFFD بهدوء، لذلك يفشل فك التشفير الذي لا يمكن أن يكون صحيحًا بدلاً من إرجاع هراء يبدو معقولاً. هذا هو المسار الذي تستخدمه مجموعة الأدوات هذه، ولهذا السبب تجمع الرموز التعبيرية والعلامات النصية من اليمين إلى اليسار ذهابًا وإيابًا تمامًا.

  1. قم بتحويل النص إلى بايت باستخدام TextEncoder - لا تقم أبدًا بالفهرسة في السلسلة.
  2. تشفير البايتات إلى base64.
  3. للعكس: فك تشفير base64 إلى بايت، ثم فك تشفير البايتات كـ UTF-8 مع القيمة القاتلة: true.
  4. إذا فشلت الخطوة UTF-8، فستكون الحمولة ثنائية وليست نصية. أظهرها على أنها سداسية بدلاً من التظاهر.

base64 مقابل base64url، وسؤال الحشو

يستخدم base64 القياسي + و/ كآخر رمزين له. كلاهما ذو معنى في عناوين URL: + يمكن قراءته كمسافة مشفرة في سلاسل الاستعلام، و/ هو فاصل المسار. لذا فإن RFC 4648 يحدد أبجدية ثانية، base64url، والتي تحل محل - و _ بدلاً من ذلك. تستخدمه JWTs، كما تفعل معظم تنسيقات الرموز المميزة والعديد من واجهات برمجة التطبيقات (APIs).

الحشو هو المتغير الآخر. منصات base64 القياسية مع = بحيث يكون طول الإخراج دائمًا مضاعفًا للأربعة. عادةً ما يحذف base64url الحشو، لأن = هو في حد ذاته حرف غريب في URL ويمكن استرداد الطول حسابيًا. وحدة فك الترميز التي تصر على الحشو سترفض مقاطع JWT الصالحة تمامًا.

نصيحة عملية: يجب أن يقبل جهاز فك التشفير الخاص بك كلا الحروف الهجائية ويتسامح مع الحشو المفقود، لأنك نادرًا ما تتحكم في ما يتم تسليمه إليك. يجب أن يكون برنامج التشفير الخاص بك واضحًا فيما يتعلق بما ينبعث منه، لأن المتلقي ربما يهتم. تقوم الأداة المساعدة base64 هنا بذلك تمامًا - فهي تقبل أي شيء معقول وتتيح لك اختيار ما تنتجه بدقة.

encodeURI وencodeURIComponent: الفرق في جملة واحدة

يتم ترميز كلا النسبة المئوية باستخدام UTF-8. إنهم يختلفون فقط في الأحرف التي يتركونها بمفردهم، وهذا الاختلاف هو القصة بأكملها: يهرب encodeURIComponent من المحددات المحجوزة، بينما لا يفعل ذلك encodeURI.

المحددات المحجوزة هي الأحرف التي تعطي URL بنيتها: : / ? # [ ] @ ! $ & ' ( ) * + , ; =. يفترض encodeURI أنك سلمته URL الذي تم تنظيمه بشكل صحيح بالفعل ويجب أن يظل على هذا النحو، لذا فهو يحافظ عليه - ولن يحول https:// إلى https%3A%2F%2F. يفترض encodeURIComponent أنك سلمته قطعة واحدة سيتم إسقاطها في الفتحة، لذلك يفلت منها، مما يضمن عدم إمكانية خروج القطعة من الفتحة الخاصة بها.

الخطأ الناتج عن هذا ميكانيكي تمامًا. خذ قيمة البحث a&b=c. قم بتشفيره باستخدام encodeURI وألحقه كـ ?q=a&b=c، وقمت بإنشاء معلمتين بصمت: q أصبح الآن مجرد "a"، وظهر b=c الضال. قم بتشفيرها باستخدام encodeURIComponent وستحصل على ?q=a%26b%3Dc، معلمة واحدة، القيمة الصحيحة. تتيح نفس فئة الأخطاء لقيمة معدة إدخال معلمات في URL الذي تنشئه التعليمات البرمجية الخاصة بك - ولهذا السبب يعد "استخدام نموذج المكون للقيم" قاعدة أمان، وليس مجرد قاعدة صحيحة.

ترميز النموذج هو القاعدة الثالثة التي تشبه القاعدة الثانية. يكتب التطبيق/x-www-form-urlencoded مسافة كـ + بدلاً من %20. إذا قمت بفك تشفير نص النموذج باستخدام decodeURIComponent العادي، فإن كل علامة زائد في البيانات تصبح مسافة. كل مربع بحث قام بتشويه "C++" إلى "C" هو هذا الخطأ.

كيانات HTML، ولماذا يعتبر فك تشفيرها باستخدام لغة HTML الداخلية عادة سيئة

الهروب إلى HTML ضيق ومفهوم جيدًا: & يصبح &amp;، < يصبح &lt;، > يصبح &gt;، وداخل قيم السمات " و ' بحاجة إلى الهروب أيضًا. خمسة أحرف. كان الهروب أكثر من ذلك - تحويل كل حرف مميز إلى كيان مسمى - بمثابة حل بديل لأيام ترميزات الأحرف غير المؤكدة، وهو الآن اختياري التصميم بدلا من السلامة.

فك التشفير هو المكان الذي تعيش فيه العادة السيئة. الحيلة المكونة من سطر واحد والتي تظهر في كل إجابة هي تعيين السلسلة إلى HTML الداخلي للعنصر المنفصل وإعادة قراءة محتوى النص الخاص به. إنها تعمل، وهي فكرة سيئة. لقد قمت بتسليم مدخلات غير موثوق بها إلى المحلل اللغوي HTML، الذي يقوم ببناء عقد DOM حقيقية منه. يصبح <img src=x onerror=...> في تلك السلسلة عنصر صورة فعليًا مع إرفاق معالج خطأ فعلي؛ إذا تم إدراج تلك الشجرة الفرعية في المستند، فسيتم تشغيلها. كما أنه يدمر بياناتك بصمت: تختفي العلامات الموجودة في الإدخال بدلاً من التعثر، لأن المحلل اللغوي يفسرها على أنها علامات بدلاً من النص.

لا يحتاج فك تشفير الكيانات بشكل صحيح إلى محلل على الإطلاق: قم بمطابقة المرجع، أو ابحث عن الاسم في جدول، أو قم بإجراء العمليات الحسابية لمرجع رقمي. هذه بضع عشرات من الأسطر، ولا يمكنها تنفيذ أي شيء، وهي تتنقل ذهابًا وإيابًا بأمانة. تقوم مجموعة الأدوات هذه بهذه الطريقة، ولهذا السبب فإن لصق علامة البرنامج النصي في وحدة فك ترميز الكيان يظهر لك علامة البرنامج النصي.

اختيار التجزئة، والأسئلة الثلاثة التي تقرر ذلك

يقوم تجزئة التشفير بتحويل أي مدخلات إلى ملخص ثابت الطول، بحيث يكون من غير الممكن العثور على مدخلين بنفس الملخص. هذه الخاصية هي ما يتيح للملخص أن يحل محل البيانات - في التوقيع، أو التحقق من السلامة، أو عنوان المحتوى.

السؤال الأول: هل تحمي من حادث أم من خصم؟ يحتاج المجموع الاختباري للحماية من التنزيلات التالفة فقط إلى التقاط تقلبات عشوائية؛ CRC32 جيد. يحتاج الملخص الذي يمكن أن يستفيد منه المهاجم من الاصطدام إلى تجزئة لا تزال قائمة. هذا التمييز هو السبب في أن SHA-1 ليس مجرد "قديم".

SHA-1 مكسورة بشكل ملموس. في 2017، أنتج العمل SHAttered ملفين مختلفين PDF بنفس الملخص SHA-1. في 2020، "SHA-1 عبارة عن فوضى" أظهر تصادم البادئة المختارة - البديل الأقوى والأكثر خطورة بكثير، لأنه يسمح للمهاجم بتصادم مستندين مختلفين بشكل مفيد بدلاً من نقطتين تم إنشاؤهما بعناية. إذا كان أمان النظام يعتمد على SHA-1 مقاومة الاصطدام، فهذا يعني أن هذا الأمان قد انتهى. يظل SHA-1 في مجموعة الأدوات هذه لأن معرفات كائنات git والتوقيعات الطويلة API لا تزال تستخدمه، ويجب أن تكون قادرًا على إعادة إنتاج هذه القيم. إن إعادة إنتاج القيمة لا يعني الاعتماد عليها.

السؤال الثاني: هل الإدخال كلمة مرور؟ إذا كان الأمر كذلك، فلا شيء من هذه هو الجواب. تم تصميم SHA-256 ليكون سريعًا، والسرعة خاطئة تمامًا بالنسبة لكلمات المرور: فهي تعني أن المهاجم الذي لديه قاعدة بياناتك يمكنه تجربة مليارات التخمينات في الثانية. تحتاج كلمات المرور إلى وظيفة بطيئة ومستنزفة للذاكرة بشكل متعمد مع ملح لكل مستخدم - Argon2id أو scrypt أو bcrypt. هذا ليس فارق بسيط. يعد استخدام SHA-256 لكلمات المرور من أكثر أخطاء التجزئة الخطيرة شيوعًا.

السؤال الثالث: هل تحتاج إلى ملخص مفاتيح؟ إذا كنت تقوم بمصادقة رسالة بدلاً من أخذ بصماتها، فأنت تريد HMAC، وليس تجزئة مجردة. يعد ربط السر وتجزئته هدفًا كلاسيكيًا في مرماه ضد الهجمات الممتدة؛ HMAC موجود لأن تنفيذ هذا البناء أصعب مما يبدو.

بالنسبة لكل شيء آخر - أخذ بصمات ملف، وعنوان محتوى، وسمة التكامل - SHA-256 هو الإعداد الافتراضي المعقول، وSHA-512 غالبًا ما يكون أسرع على أجهزة 64 بت مع توفير ملخص أوسع.

لماذا تأتي التجزئات هنا من المتصفح

يتم حساب الملخصات الموجودة في مجموعة الأدوات هذه بواسطة SubtleCrypto، وهو تطبيق Web Crypto الخاص بالمتصفح، وليس بواسطة JavaScript الذي يتم شحنه من هذا الموقع. يعد هذا اختيارًا متعمدًا: تتم مراجعة تنفيذ المتصفح وصيانته وتشغيله عادةً كرمز أصلي محسّن. يعد SHA-256 المكتوب بخط اليد في حزمة الصفحات بمثابة رمز أكثر يمكن الاعتماد عليه دون أي فائدة.

ولها نتيجة واحدة واضحة. يتم عرض تشفير الويب فقط في سياق آمن، أي https:// أو المضيف المحلي. افتح هذه الصفحة على عنوان HTTP العادي على عنوان LAN وسيكون crypto.subtle غير محدد، لذا ستخبرك أداة التجزئة بذلك بوضوح بدلاً من الفشل بصمت أو استبدال شيء أضعف.

نفس المنطق يقود المولد UUID. crypto.randomUUID() هو أيضًا سياق آمن فقط، لذلك عندما لا يكون متاحًا، ترجع مجموعة الأدوات إلى crypto.getRandomValues() - والذي لا يزال نفس المصدر الآمن للتشفير - ويقوم بتعيين الإصدار والبت المتغير بنفسه. ما لن يفعله أبدًا هو الرجوع إلى Math.random(). هذا برنامج سريع غير مشفر PRNG يمكن استعادة حالته الداخلية من مسافة قصيرة من مخرجاته، والمعرفات لديها عادة مؤسفة تتمثل في الترويج لمفاتيح الجلسة وروابط إعادة تعيين كلمة المرور. في حالة عدم وجود مصدر آمن، فإن هذه الأداة لا تولد أي شيء وتوضح السبب.

ماذا يحدث لما تلصقه

  • يتم تشغيل كل تحويل وتجزئة وفك تشفير وفرق في علامة تبويب المتصفح الخاص بك. لا يتم تحميل أي مدخلات أو تسجيلها أو تخزينها على الخادم، لأنه لا يوجد خادم مشارك بمجرد تحميل الصفحة.
  • تأتي التجزئة من تطبيق Web Crypto الخاص بالمتصفح، والمعرفات الفريدة الفريدة (UUID) من المولد العشوائي الآمن للتشفير. لا يتضمن أي منهما مكالمة شبكة.
  • لا تتم كتابة أي شيء تكتبه على وحدة التخزين المحلية أو ملف تعريف الارتباط. تؤدي إعادة تحميل الصفحة إلى تجاهلها؛ إغلاق علامة التبويب يتجاهلها.
  • يتم تشغيل التحليلات على مستوى الموقع فقط على مضيف الإنتاج الأساسي الذي تم تكوينه ويتم الكشف عنها في سياسة الخصوصية؛ المضيفون المحليون ومضيفو المعاينة يرفضون ذلك. يتم استبعاد القيم والرموز المميزة وعناوين URL ومحتويات الملفات التي تم لصقها من أحداث التحليلات الخاصة بـ ToolAcre. تم تعطيل الإعلان في التكوين الحالي.
  • ومع ذلك: يعد المفتاح JWT أو المفتاح API بمثابة بيانات اعتماد مباشرة. العادة الآمنة هي عدم لصق أي شيء على صفحة ويب لم تكتبها، مهما كانت ادعاءاتها جديرة بالثقة - بما في ذلك هذه الصفحة.

أسئلة

هل base64 وسيلة لإخفاء البيانات؟

لا، إنه تمثيل نصي قابل للعكس بدون مفتاح، ويمكن لأي شخص فك تشفيره في جزء من الثانية. فهو يجعل البيانات تبقى على قيد الحياة في القنوات النصية فقط؛ لا يجعلها سرا. أي شيء حساس حقًا يحتاج إلى تشفير، وغالبًا ما تكون النتيجة المشفرة مشفرة باستخدام قاعدة 64 للنقل - وهو مصدر الارتباك.

لماذا يكون Base64 الخاص بي أطول من الإدخال؟

نظرًا لأن أربعة أحرف إخراج تحمل ثلاثة بايتات إدخال، فإن حجم الإخراج هو 4/3 تقريبًا، بالإضافة إلى ما يصل إلى حرفين من الحشو. وهذا متأصل في الشكل. إذا كان الحجم مهمًا، فاضغط قبل التشفير - وليس بعد ذلك أبدًا، لأن ضغط مخرجات base64 يكون ضعيفًا.

ما هي وظيفة التشفير URL التي يجب أن أستخدمها؟

استخدم encodeURIComponent لأي قطعة منفردة تقوم بإدراجها في URL: قيمة استعلام، أو مقطع مسار، أو جزء. استخدم encodeURI فقط عندما يكون لديك URL كامل ومنظم بالفعل ويحتوي فقط على مسافات أو غير ASCII. إذا كنت تقوم بإنشاء سلسلة استعلام، ففضل URLSearchParams، الذي يطبق القاعدة الصحيحة لك ويتعامل مع اختلاف المسافة كعلامة زائد.

لماذا تظهر وحدة فك الترميز الخاصة بي "URI مشوهة"؟

لأن % في الإدخال لا يتبعه رقمان سداسي عشري. عادةً ما يحتوي النص على علامة نسبة مئوية حرفية - "50% off" - والتي لم يتم ترميزها مطلقًا. يجب كتابة النسبة المئوية الحرفية بالشكل %25. تقوم الأداة المساعدة URL هنا بالإبلاغ عن الموقع الدقيق للهروب المخالف بدلاً من مجرد الرفض.

هل يمكنني استخدام SHA-256 لتخزين كلمات المرور؟

لا. SHA-256 سريع التصميم، مما يعني أن المهاجم الذي يسرق قاعدة البيانات الخاصة بك يمكنه اختبار مليارات كلمات المرور المرشحة في الثانية على الأجهزة السلعية. تحتاج كلمات المرور إلى وظيفة بطيئة ومستنزفة للذاكرة ومملحة: Argon2id أو scrypt أو bcrypt. وهذا هو الخطأ الجسيم الأكثر شيوعا في هذا المجال.

لماذا لا يزال SHA-1 موجودًا إذا تم كسره؟

لأنك لا تزال بحاجة إلى إعادة إنتاج SHA-1 القيم الموجودة بالفعل: معرفات كائنات git، وبصمات شهادة TLS القديمة، وتوقيعات الطلب API القديمة. تختلف القدرة على حساب قيمة قابلية التشغيل البيني عن الاعتماد عليها للأمان. يتم تصنيف كل مكان يظهر SHA-1 في مجموعة الأدوات هذه وفقًا لذلك.

لماذا تعطي أداتان تجزئات مختلفة لنفس النص؟

دائمًا ما يكون هناك اختلاف في البايتات، وليس في الخوارزمية. الأسباب المعتادة هي سطر جديد لاحق (ينتهي الملف بسطر واحد، وقد لا ينتهي مربع النص)، أو ترميز نص مختلف، أو CRLF مقابل نهايات سطر LF. تقوم هذه الأداة بتجزئة UTF-8 بايت لما كتبته بالضبط وتظهر لك عدد البايتات، مما يجعل التناقض واضحًا في العادة.

القيود

  • يغطي جدول الكيانات HTML المجموعة الفرعية العملية - الأحرف الترميزية المهمة، والطباعة، والعملة، والأسهم، والرياضيات، واليونانية واللاتينية- 1 - وليس كل 2,231 HTML5 المراجع المسماة. يتم الإبلاغ عن الأسماء غير المعروفة ويتم تركها تمامًا كما هي مكتوبة بدلاً من تخمينها.
  • يتطلب فك تشفير الكيان فاصلة منقوطة للإنهاء. HTML5 يسمح بعدد قليل من المراجع القديمة بدون مرجع واحد، ولكن فك تشفيرها بشكل صحيح يعتمد على سياق العلامات المحيط، وهو ما لا تتوفر فيه أداة النص المستقلة.
  • يحتاج التجزئة وإنشاء UUID إلى سياق آمن (https:// أو مضيف محلي) لأن Web Crypto لن يتم كشفه بطريقة أخرى. تقوم الأداة بالإبلاغ عن هذا بدلاً من استبدال تطبيق أضعف.
  • تتوفر فقط SHA-1 وSHA-256 وSHA-384 وSHA-512، لأن هذه هي ما تنفذه SubtleCrypto. MD5 غائب بالاختيار وكذلك بالضرورة.
  • لا يوجد HMAC، ولا يوجد اشتقاق مفتاح ولا تشفير هنا. يحتاج هؤلاء إلى إدارة المفاتيح، وهو أمر لا يجب أن تتعامل معه الصفحة التي وجدتها على الإنترنت.
  • كل شيء مقيد بذاكرة جهازك، حيث يتم تشغيله جميعًا في علامة تبويب متصفح واحدة. يتم وضع حد أقصى للمدخلات - بضعة ميغابايت لكل أداة مساعدة - وترفض الأداة العمل الكبير الحجم بدلاً من التجميد.