SSD Nodes Learn 🎉 VPS من $5.50/شهر
الأدلة Matt Connorبقلم Matt Connor

كيفية التحقق من سلامة الملفات عبر checksum في لينكس

تعلم كيفية التحقق من سلامة ملفاتك باستخدام أمر sha256sum ومطابقتها مع ملف SHA256SUMS. سنقوم بتجربة عملية لتخريب الملف عمداً ورؤية رسالة الخطأ لضمان فهمك لكيفية عمل البصمات الرقمية.

التحقق من تنزيل ملف باستخدام المجموع الاختباري في دقيقتين

للتحقق من تنزيل ملف باستخدام المجموع الاختباري (checksum)، قم بحساب بصمة الملف الذي استلمته ودع الأداة تقارن هذه البصمة بتلك التي نشرها المطور. تقوم sha256sum بكلا شقي المهمة: فهي تطبع البصمة بمفردها، ومع الخيار -c تقرأ قائمة البصمات وتحدد الملفات المطابقة. يُجري هذا الدليل العملية كاملة على ملف تنشئه بنفسك، ثم يقوم بتخريب الملف عمداً لتشاهد الفشل بنفسك بدلاً من الاكتفاء بالقراءة عنه.

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

إنشاء ملف للتدرّب

اعمل داخل دليل مؤقت لضمان عدم تأثير أي إجراء على بقية النظام. كل أمر أدناه جزء من GNU coreutils، وهي مجموعة الأوامر الأساسية الموجودة في أي خادم Ubuntu أو Debian، لذا لا تحتاج إلى تثبيت أي شيء.

mkdir -p ~/checksum-demo
cd ~/checksum-demo
printf 'the payload of a totally ordinary download\n' > payload.txt
sha256sum payload.txt

ستحصل على سطر واحد: 64 رمزاً ست عشرياً، متبوعاً بمسافتين، ثم اسم الملف. هذه الرموز الـ 64 هي بصمة الملف (digest). نفّذ الأمر مجدداً وستجد السطر مطابقاً تماماً، لأن عملية التجزئة (hashing) حتمية: المدخلات نفسها تعطي دائماً المخرجات نفسها. غيّر حرفاً واحداً في الملف ونفّذ الأمر مرة أخرى، ولن تتغير البصمة قليلاً فحسب، بل ستبدو مختلفة تماماً، لأن تغيير بت واحد في المدخلات يقلب حوالي نصف بتات المخرجات. هذه الخاصية هي ما يجعل سلسلة من 64 رمزاً بديلاً صالحاً لتمثيل ملف صورة بحجم 4 GB.

حفظ ملف SHA256SUMS ثم التحقق منه

إنّ عرض ملخص التجزئة (digest) على الشاشة لا يفيد بعد مرور يوم. احفظه في ملف بالتنسيق الذي يكتبه sha256sum نفسه، لكي تتمكن الأداة من قراءته لاحقاً.

sha256sum payload.txt > SHA256SUMS
cat SHA256SUMS
sha256sum -c SHA256SUMS

يقرأ sha256sum -c كل سطر في القائمة، ويحسب قيمة التجزئة للملف المذكور في ذلك السطر، ثم يقارن بين القيمتين. في حال كانت العملية سليمة، سيطبع البرنامج سطراً واحداً لكل ملف:

payload.txt: OK

تحقق أيضاً من حالة الخروج (exit status)، لأن البرامج النصية تقرأ هذه الحالة ولا تقرأ النص. يطبع echo $? القيمة 0 بعد تنفيذ ناجح. اسم الملف SHA256SUMS هو اصطلاح وليس قاعدة، لكن التوزيعات ومعظم صفحات الإصدارات تستخدمه، لذا استخدمه أنت أيضاً ليعرف الشخص التالي محتوى الملف دون الحاجة لفتحه.

غيّر بايت واحد وشاهد فشل التحقق

الآن، تعمّد إتلاف الملف. يكتب هذا الأمر بايت واحداً عند الإزاحة 5 ويترك باقي الملف كما هو، لذا يحافظ الملف على طوله واسمه.

printf 'X' | dd of=payload.txt bs=1 seek=5 conv=notrunc status=none
cat payload.txt
sha256sum -c SHA256SUMS

conv=notrunc هو العلم المهم هنا: بدونه، يقوم dd باقتطاع الملف عند النقطة التي يتوقف فيها عن الكتابة، وبذلك ستختبر نوعاً أكثر وضوحاً من التلف. يطبع التحقق الآن:

payload.txt: FAILED
sha256sum: WARNING: 1 computed checksum did NOT match

يطبع echo $? القيمة 1. تعني FAILED أن الملف قد قُرئ وأن بصمته لم تطابق تلك الموجودة في القائمة. أعد البايتات الأصلية وتأكد من أن التحقق يعود إلى OK:

printf 'the payload of a totally ordinary download\n' > payload.txt
sha256sum -c SHA256SUMS

هذه هي العادة بأكملها. بايت واحد من الاختلاف، في أي مكان في الملف، ينتج FAILED. تنزيل مقطوع بسبب فقدان الاتصال، أو مرآة (mirror) تقدم إصدار الأمس، أو وكيل (proxy) أعاد كتابة الملف أثناء النقل، أو قرص أعاد كتلة تالفة: كلها تؤدي إلى نفس النتيجة.

عندما تتضمن القائمة ملفاً لم تقم بتنزيله

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

printf 'a second file\n' > notes.txt
sha256sum payload.txt notes.txt > SHA256SUMS.all
rm notes.txt
sha256sum -c SHA256SUMS.all
payload.txt: OK
sha256sum: notes.txt: No such file or directory
notes.txt: FAILED open or read
sha256sum: WARNING: 1 listed file could not be read

يُعد FAILED open or read خطأً مختلفاً عن FAILED، والخلط بينهما يضيع الوقت. يعني FAILED أن البايتات غير صحيحة. بينما يعني FAILED open or read أن sha256sum لم يحصل على الملف نهائياً، لذا لم تتم أي مقارنة. في التنزيلات الحقيقية، السبب المعتاد هو دليل العمل الحالي، لأن الأسماء في القائمة تكون نسبية للمكان الذي تنفذ فيه الأمر. انتقل إلى الدليل الذي يحتوي على الملف وأعد تنفيذ الأمر. للتحقق فقط مما تملكه فعلياً، اطلب ذلك تحديداً:

sha256sum --ignore-missing -c SHA256SUMS.all

يطبع ذلك payload.txt: OK ويخرج برمز الحالة 0. إذا لم يكن أي من الأسماء المدرجة موجوداً، فإن --ignore-missing لا ينجح بصمت مع صفر من الملفات. بل يبلغ أن no file was verified ويخرج برمز حالة غير صفري، وهو السلوك الذي تريده، لأن عملية التحقق التي لم تفحص شيئاً هي الفشل الذي لن تلاحظه أبداً.

لصق ملخص منشور دون فحصه بصرياً

تكمن المشكلة الحقيقية في عادة مقارنة 64 محرفاً ست عشرياً بالعين. يكتفي المستخدمون بالتحقق من المحارف الأربعة الأولى والأخيرة ويعدّونها مطابقة، وهذا بالضبط ما يتوقعه المهاجم المصمم. دع الأداة تقوم بالمقارنة بدلاً منك. اضبط EXPECTED على الملخص الذي نسخته من الناشر، باستخدام EXPECTED= متبوعاً بالقيمة التي لصقتها، ثم أنشئ السطر الواحد الذي يتوقعه -c:

printf '%s  %s\n' "$EXPECTED" payload.txt > payload.sha256
cat payload.sha256
sha256sum -c payload.sha256

توجد مسافتان بين الملخص واسم الملف، ولهذا السبب يحتوي نص التنسيق على مسافتين. هذا هو الشكل الذي يكتبه sha256sum والشكل الذي يحلله -c. الملف الذي يحتوي على ملخص فقط لا يُعد سطر مجموع اختباري (checksum)، لذا يرفض الفحص الملف بالكامل مع no properly formatted checksum lines found بدلاً من تخمين الملف الذي تقصده. تنشر بعض المشاريع نمط BSD الموّسم بدلاً من ذلك، SHA256 (payload.txt) = متبوعاً بالملخص. تكتب أدوات GNU coreutils هذا الشكل باستخدام sha256sum --tag payload.txt وتقرؤه باستخدام -c، لذا فإن كلا الشكلين صالح للحفظ.

عندما يتصرف الفحص بشكل غريب، انظر إلى القائمة نفسها باستخدام cat -A SHA256SUMS، الذي يحدد نهاية كل سطر بـ $ ويعرض المحارف التي لا يمكنك رؤيتها بخلاف ذلك. السطر الذي ينتهي بـ ^M$ التقط محرف إرجاع (carriage return) من محرر Windows. يتجاهل GNU sha256sum هذا المحرف اللاحق ويطبع مع ذلك OK، لذا فإن قائمة CRLF ليست هي ما يكسر الفحص الخاص بك، على الرغم من أن الأدوات خارج coreutils أقل تسامحاً مع ذلك. قم بتطبيع النسخة التي تحتفظ بها باستخدام tr -d '\r' < SHA256SUMS > SHA256SUMS.clean.

ما الذي يثبته المجموع الاختباري (checksum)، وما الذي لا يثبته؟

يثبت المجموع الاختباري شيئاً واحداً: البايتات الموجودة على قرصك هي ذاتها التي أنتجت البصمة المنشورة. هذا يغطي التلف العرضي بالكامل. كما يغطي المهاجم المهمل الذي استبدل الملف على مرآة تحميل (download mirror) لكنه لم يستطع الوصول إلى الصفحة التي نشرت البصمة.

إنه لا يثبت شيئاً عن هوية المؤلف. البصمة هي حقيقة تتعلق بالبايتات، وليست حقيقة تتعلق بالأشخاص. إذا كانت الصفحة نفسها توفر الملف والبصمة، فإن من يستطيع تغيير أحدهما يمكنه تغيير الآخر، وسطر OK الخاص بك يعني فقط أن المرآة متوافقة مع نفسها. لذا، إليك القاعدة التي تجعل تشغيل المجموع الاختباري مفيداً: احصل على البصمة من مصدر مختلف عن المصدر الذي حصلت منه على الملف. على سبيل المثال، احصل عليها من نطاق المشروع الرسمي عبر TLS (أمن طبقة النقل) بينما تأتي الصورة من مرآة أو عبر تورنت. الآن، يجب على المهاجم السيطرة على مكانين بدلاً من مكان واحد.

الخوارزمية مهمة أيضاً. لا توجد تصادمات معروفة لخوارزمية SHA-256 (خوارزمية التجزئة الآمنة، مخرجات 256 بت) حتى أغسطس 2026، ولهذا السبب يستخدمها الناشرون. أما MD5 (ملخص الرسالة 5) وSHA-1 فلم تعودا صامدتين: فقد أمكن إنشاء ملفين مختلفين لهما نفس بصمة MD5 منذ عام 2004، ونُشر تصادم SHA-1 ببادئة مختارة في عام 2020. لا يزال ملف MD5SUMS يكتشف التحميل الناقص، لأن التلف العشوائي ليس تصادماً مصمماً. لكنه لا يستطيع إيقاف شخص يحاول خداعك. عندما ينشر مشروع ما كليهما، اعتمد سطر SHA-256.

حيث تتولى التوقيعات المسؤولية

يغلق التوقيع الفجوة التي يتركها الملخص (digest) مفتوحة. يوقّع الناشر ملف الملخص باستخدام مفتاح خاص، وتتحقق أنت منه باستخدام مفتاحهم العام: gpg --verify SHA256SUMS.asc SHA256SUMS. إذا نجحت العملية، فهذا يعني أن قائمة الملخصات صادرة عن الجهة التي تمتلك ذلك المفتاح. بعد ذلك، يربط sha256sum -c SHA256SUMS الملف الموجود على قرصك بالقائمة، وتمتد سلسلة الثقة من المفتاح وصولاً إلى البايتات.

تنتقل نقطة الضعف إلى المفتاح. جلب المفتاح من نفس الصفحة التي وفّرت الملف يمنح المهاجم كلا الجزأين. برنامج GnuPG صريح بشأن هذا الأمر، حيث يطبع عند التحقق الأول Good signature مع WARNING: This key is not certified with a trusted signature!. تعني Good signature أن الرياضيات صحيحة. لكنها لا تعني أن المفتاح ينتمي فعلياً إلى المشروع الذي تقصده. احصل على البصمة (fingerprint) من مصدر ثانٍ، مثل وثائق المشروع على نطاق مختلف أو حزمة توزيع تتضمن المفتاح مسبقاً، وقارن البصمة الكاملة بدلاً من الاكتفاء بآخر ثمانية محارف. هذا يتطلب نفس القدر من العناية الذي يستحقه مفتاح SSH الخاص، ولنفس السبب: المفتاح هو قرار الثقة، وكل ما يليه يرث هذه الثقة.

تدفع عمليات البناء القابلة للتكرار (reproducible builds) هذه الفكرة خطوة إضافية. الملخص المنشور يربطك بملف ثنائي بناه جهاز واحد. عندما يكون بناء المشروع قابلاً للتكرار، يمكن لأي شخص تجميع نفس المصدر والحصول على مخرجات متطابقة بايت ببايت، مما يسمح لبناة مستقلين بتأكيد الملخص المنشور بدلاً من مطالبتك بالاعتماد على كلمة خادم واحد. تزداد أهمية هذا الأمر عاماً بعد عام، مع وصول المزيد من التعليمات البرمجية عبر خطوط أنابيب مؤتمتة وتصحيحات مكتوبة آلياً. إن تحديد ما تقبله في عملية البناء هو مسألة سياسة، وتعمل سياسات المصادر المفتوحة للتعليمات البرمجية المدعومة بالذكاء الاصطناعي على نفس سلسلة التوريد من الطرف الآخر.

مدير الحزم لديك يقوم بهذا العمل نيابة عنك

على توزيعتي Debian و Ubuntu، يقوم apt بتنفيذ هذه السلسلة مع كل عملية تثبيت دون الحاجة لطلب ذلك. يحتوي فهرس الحزم على بصمة SHA-256 لكل ملف .deb. يحمل الملف Release بصمات ملفات الفهرس تلك، بينما يحمل الملف InRelease توقيعاً رقمياً للملف Release، يتم التحقق منه مقابل المفاتيح الموجودة في /usr/share/keyrings و /etc/apt/trusted.gpg.d. عندما تنكسر هذه السلسلة، يخبرك apt بذلك: يظهر الخطأ The following signatures couldn't be verified because the public key is not available: NO_PUBKEY عند فقدان مفتاح مستودع تابع لجهة خارجية، أو يظهر الخطأ Hash Sum mismatch عندما لا يطابق الفهرس الذي جلبته الملف Release الموقّع، وهو ما يعني عادةً أن وكيل التخزين المؤقت (caching proxy) قد قدّم ملفاً قديماً أو أنك اتصلت بمرآة (mirror) أثناء عملية المزامنة.

هذا هو المعيار الذي يجب القياس عليه عندما تطلب منك الصفحة الرئيسية لأحد المشاريع تمرير (pipe) سكربت من curl مباشرة إلى الصدفة (shell). لا يوجد شيء يتحقق من البايتات ولا يمكنك رؤيتها أبداً. يمكن للخادم أيضاً إرجاع محتوى مختلف للسكربت عما يظهر في المتصفح، ولن تملك نسخة لفحصها لاحقاً. قم بتنزيل الملف باستخدام curl -fsSL <url> -o install.sh، ثم احسب بصمته (hash)، واقرأ محتواه باستخدام less، ولا تقم بتشغيله إلا بعد ذلك. هذه العادة تستغرق حوالي عشرين ثانية، وهي نفس العادة التي تستحق البدء بها على خادم VPS جديد في دقائقه العشر الأولى، قبل تثبيت أي شيء آخر على الجهاز.

احتفظ بقائمة بصمات رقمية لما تثبته يدوياً

يتم تتبع الحزم المثبتة بواسطة apt. أما الملف الثنائي الذي نسخته إلى /usr/local/bin فلا يتم تتبعه، ولا يوجد شيء في النظام يراقبه. تحوّل قائمة البصمات الرقمية (digests) هذا الملف إلى شيء يمكنك التحقق منه عند الطلب:

printf 'a second file\n' > notes.txt
sha256sum *.txt > inventory.sha256
sha256sum -c --quiet inventory.sha256

لا يطبع --quiet أي شيء عندما تتطابق جميع الملفات، ويطبع فقط الأسطر التي فشلت عند وجود عدم تطابق، لذا فإن الصمت يعني النجاح، ويؤكد echo $? ذلك باستخدام 0. هذا هو التنسيق الذي يجب وضعه في مهمة مجدولة. يذهب --status إلى أبعد من ذلك ولا يطبع شيئاً على الإطلاق، تاركاً لك حالة الخروج فقط. وجّه النمط نفسه نحو الملفات الحقيقية باستخدام sha256sum /usr/local/bin/* > ~/local-bin.sha256 وستحصل على خط أساس. تُخزّن المسارات في القائمة تماماً كما كتبتها، لذا فإن استخدام المسارات المطلقة يجعل الفحص يعمل من أي دليل.

كن واضحاً بشأن قيمة خط الأساس هذا. فهو يكتشف الملفات المُعدّلة. لكنه لا يكتشف المهاجم الذي يمتلك صلاحيات root بالفعل، لأن هذا المهاجم يمكنه إعادة كتابة inventory.sha256 بسهولة كما أعاد كتابة الملف الثنائي. احتفظ بالقائمة خارج الجهاز إذا كنت تريد لها أن تعني شيئاً، وهذا جزء من السؤال الأوسع حول مقدار الثقة التي تمنحها لخادم VPS الخاص بك ومن يمكنه الوصول إلى القرص تحته.

FAQ

هل يعني تطابق المجموع الاختباري (checksum) أن التنزيل آمن؟

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

لماذا يطبع sha256sum -c رسالة FAILED open or read؟

لأنه لم يقرأ الملف. يظهر سطر منفصل فوقه مباشرة يوضح No such file or directory مع الاسم الذي بحث عنه. الأسماء داخل ملف SHA256SUMS تكون نسبية للمجلد الذي تشغل الأمر فيه، لذا انتقل إلى المجلد الذي يحتوي على الملف الذي قمت بتنزيله وشغّل الأمر مجدداً. إذا كانت القائمة تحتوي أيضاً على أسماء ملفات لم تقم بتنزيلها، أضف --ignore-missing. أما ظهور FAILED صريح بدون open or read فيعني حالة معاكسة: لقد تمت قراءة الملف، لكن بصمته لم تتطابق.

هل MD5 كافٍ للتحقق من التنزيل؟

للتلف العرضي، نعم. النقل غير المكتمل أو قطاع القرص التالف لن ينتج بصمة MD5 مطابقة بالصدفة. أما ضد المهاجمين، فلا. يمكن بناء ملفين مختلفين لهما نفس بصمة MD5 منذ عام 2004، كما سقطت SHA-1 أمام هجمات التصادم (collision) في عام 2020. اعتمد سطر SHA-256 عندما ينشر المشروع كلاهما، واعتبر الاعتماد على MD5 فقط مؤشراً على عملية إصدار قديمة.

ما الفرق بين sha256sum -c و gpg --verify؟

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

كيف أتحقق من ملف واحد مقابل بصمة منشورة على صفحة ويب؟

لا تقارن الأحرف بالعين المجردة. احفظ البصمة واسم الملف في سطر واحد، مفصولين بمسافتين، ثم شغّل sha256sum -c مقابل ذلك الملف واقرأ OK أو FAILED التي يطبعها. بناء السطر باستخدام printf '%s %s\n' يتجنب أخطاء التنسيق التي تجعل sha256sum يرفض الملف مع رسالة no properly formatted checksum lines found.

#checksums#sha256sum#integrity#supply-chain#أمان