SSD Nodes Learn 🎉 VPS החל מ־$5.50/חודש
מדריכים Matt Connorמאת Matt Connor · עודכן 2026-08-13

אימות תקינות קבצים בלינוקס באמצעות sha256sum

למדו לאמת הורדות בעזרת הפקודה sha256sum והדגל -c. המדריך מסביר איך ליצור חתימת hash, להשוות אותה לקובץ מקור ולזהות שיבושים בנתונים בעזרת תרגול מעשי של שינוי בייטים בקובץ.

אימות הורדה באמצעות checksum בשתי דקות

כדי לאמת הורדה באמצעות checksum, בצעו hashing לקובץ שקיבלתם ותנו לכלי להשוות את ה-hash לזה שפרסם המפיץ. sha256sum מבצע את שני חלקי המשימה: כשלעצמו הוא מציג digest, ועם הדגל -c הוא קורא רשימת digests ומדווח אילו קבצים תואמים. מדריך זה מריץ את התהליך המלא על קובץ שתיצרו, ולאחר מכן משבש את הקובץ בכוונה כדי שתראו את הכישלון מתרחש במקום רק לקרוא עליו.

זכרו משפט אחד לאורך כל הדרך. checksum אומר לכם האם הבייטים שבידיכם הם אותם בייטים שיצרו את ה-digest, אך הוא אינו אומר דבר על מי שיצר אותם. השאלה השנייה דורשת חתימה ומפתח שאתם סומכים עליו. החלק האחרון של מדריך זה מראה בדיוק היכן עובר הגבול בין השניים.

יצירת קובץ לתרגול

עבדו בתוך ספריית עבודה זמנית כדי להבטיח ששום דבר כאן לא ישפיע על שאר המערכת. כל פקודה להלן מגיעה מתוך 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 היא דטרמיניסטית: אותו קלט תמיד מניב את אותו פלט. שנו תו אחד בקובץ והריצו את הפקודה שוב; ה-digest לא ישתנה רק במעט. הוא ייראה שונה לחלוטין, כיוון ששינוי של ביט אחד בקלט הופך בערך מחצית מביטי הפלט. תכונה זו היא שהופכת מחרוזת של 64 תווים לתחליף שמיש עבור קובץ image של 4 GB.

שמירת קובץ SHA256SUMS ובדיקתו

ערך גיבוב (digest) שמופיע על המסך אינו מועיל לאחר יום. יש לכתוב אותו לקובץ, בפורמט שבו sha256sum עצמו כותב, כדי שהכלי יוכל לקרוא אותו בחזרה במועד מאוחר יותר.

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

sha256sum -c קורא כל שורה ברשימה, מחשב את הגיבוב של הקובץ המצוין באותה שורה, ומשווה בין שני הערכים. הרצה תקינה מדפיסה שורה אחת עבור כל קובץ:

payload.txt: OK

יש לבדוק גם את סטטוס היציאה (exit status), כיוון שסקריפטים קוראים אותו ולא את הטקסט. echo $? מדפיס 0 לאחר הרצה נקייה. השם SHA256SUMS הוא מוסכמה ולא כלל מחייב, אך הפצות ורוב דפי ה-release משתמשים בו; לכן כדאי להשתמש בו גם כן, כדי שהמשתמש הבא ידע מה מכיל הקובץ מבלי לפתוח אותו.

שינוי בייט אחד וצפייה בכישלון הבדיקה

כעת נשבש את הקובץ בכוונה. הפעולה הבאה כותבת בייט יחיד ב-offset 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 היא שהקובץ נקרא, אך ה-digest שלו לא תאם לזה שברשימה. החזירו את הבייטים המקוריים וודאו שהבדיקה חוזרת ל-OK:

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

זהו כל ההרגל. הבדל של בייט אחד, בכל מקום בקובץ, מניב FAILED. הורדה שנקטעה עקב ניתוק, שרת mirror שמגיש גרסה מאתמול, proxy שכתב מחדש את הקובץ במהלך המעבר, או דיסק שהחזיר bad block: כולם מובילים לאותה שורת פלט בדיוק.

כאשר הרשימה מציינת קובץ שלא הורדת

קובץ SHA256SUMS אמיתי מהפצה מפרט את כל קובצי ה-image שהפרויקט מפיץ, ואתה הורדת רק אחד מהם. שחזר מצב זה כאן.

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 ויסיים עם קוד יציאה שאינו 0, וזהו ההתנהגות הרצויה, שכן בדיקה שעברה בהצלחה מבלי לבדוק דבר היא כשל שלעולם לא תבחינו בו.

הדבקת תקציר שפורסם ללא בדיקה ויזואלית

השוואה ויזואלית של 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. הכלי sha256sum של GNU מתעלם מתו סיום זה ועדיין מדפיס OK, כך שרשימה בפורמט CRLF אינה הגורם לכשל בבדיקה שלכם, אם כי כלים מחוץ ל-coreutils סלחניים פחות כלפי תווים אלו. נרמלו את העותק שברשותכם באמצעות tr -d '\r' < SHA256SUMS > SHA256SUMS.clean.

מה מוכיח checksum, ומה הוא אינו מוכיח?

checksum מוכיח דבר אחד בלבד: הבתים שנמצאים על הכונן שלך הם אותם הבתים שיצרו את ה-digest שפורסם. זה מכסה באופן מלא נזק מקרי. זה מכסה גם תוקף רשלן שהחליף את הקובץ בשרת מראה (mirror) להורדות, אך לא הייתה לו גישה לדף שבו פורסם ה-digest.

הוא אינו מוכיח דבר לגבי זהות היוצר. digest הוא עובדה לגבי בתים, לא עובדה לגבי אנשים. אם דף אחד מגיש גם את הקובץ וגם את ה-digest, הרי שמי שיכול לשנות את האחד יכול לשנות גם את השני, ושורת ה-OK שלך מעידה רק על כך שהשרת מסכים עם עצמו. לכן, זהו הכלל שהופך את השימוש ב-checksum לכדאי: קחו את ה-digest ממקור שונה מזה שממנו הורדתם את הקובץ. למשל, הדומיין הרשמי של הפרויקט ב-TLS (אבטחת שכבת תעבורה), בזמן שהקובץ הגיע משרת מראה או מ-torrent. כעת, על התוקף לשלוט בשני מקומות במקום באחד.

גם לאלגוריתם יש חשיבות. ל-SHA-256 (אלגוריתם גיבוב מאובטח, פלט של 256 סיביות) אין התנגשות (collision) ידועה נכון לאוגוסט 2026, וזו הסיבה שמפרסמים משתמשים בו. MD5 (תמצית הודעה 5) ו-SHA-1 אינם עומדים במבחן: ניתן לייצר שני קבצים שונים עם אותו digest מסוג MD5 מאז 2004, והתנגשות SHA-1 עם קידומת נבחרת פורסמה ב-2020. קובץ MD5SUMS עדיין יזהה הורדה קטועה, כיוון ששיבוש אקראי אינו התנגשות מתוכננת. הוא אינו יכול לעצור מישהו שמנסה להטעות אותך. כאשר פרויקט מפרסם את שניהם, השתמשו בשורת ה-SHA-256.

היכן שחתימות נכנסות לתמונה

חתימה סוגרת את הפער שמותיר אחריו ה-digest. המפיץ חותם על קובץ ה-digest באמצעות מפתח פרטי, ואתם מאמתים זאת בעזרת המפתח הציבורי שלו: gpg --verify SHA256SUMS.asc SHA256SUMS. אם האימות עובר, רשימת ה-digests הגיעה ממי שמחזיק במפתח זה. לאחר מכן, sha256sum -c SHA256SUMS מקשר בין הקובץ שעל הדיסק שלכם לבין הרשימה, והשרשרת נמתחת מהמפתח ועד לרמת הבתים.

נקודת התורפה עוברת למפתח. משיכת המפתח מאותו דף שסיפק את הקובץ מעניקה לתוקף את שני החלקים גם יחד. GnuPG מציג זאת בגלוי, ואימות ראשוני מדפיס את Good signature יחד עם WARNING: This key is not certified with a trusted signature!. המשמעות של Good signature היא שהמתמטיקה תקינה. אין זה אומר שהמפתח שייך לפרויקט שאליו התכוונתם. השיגו את ה-fingerprint ממקור שני, כגון תיעוד הפרויקט בדומיין אחר או חבילת הפצה שכבר כוללת את המפתח, והשוו את ה-fingerprint המלא במקום את שמונת התווים האחרונים. זהו אותוירות הנדרשת עבור מפתח SSH פרטי, מאותה סיבה: המפתח הוא החלטת האמון, וכל מה שבא אחריו יורש אותה.

בנייה הדירה (Reproducible builds) מקדמת את הרעיון צעד אחד קדימה. digest מפורסם עדיין קושר אתכם לקובץ בינארי שמכונה אחת בנתה. כאשר תהליך הבנייה של פרויקט הוא הדיר, כל אחד יכול לקמפל את אותו קוד מקור ולקבל פלט זהה ברמת הבייט, כך שבוני תוכנה עצמאיים יכולים לאשר את ה-digest המפורסם במקום שתצטרכו להסתמך על מילה של שרת בודד. חשיבות הדבר גוברת מדי שנה, ככל שיותר קוד מגיע דרך צינורות אוטומטיים וטלאים שנכתבו על ידי מכונה. ההחלטה מה לקבל לתוך תהליך בנייה היא שאלת מדיניות, ו-מדיניות קוד פתוח עבור קוד בסיוע בינה מלאכותית פועלות על אותו שרשרת אספקה מהצד השני.

מנהל החבילות שלכם כבר מבצע זאת עבורכם

במערכות 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 במהלך סנכרון.

זהו הסטנדרט שיש לשאוף אליו כאשר דף הבית של פרויקט מנחה אתכם להזרים סקריפט מ-curl ישירות לתוך shell. שום דבר לא מאמת את הבתים ואתם לעולם לא רואים אותם. השרת יכול גם להחזיר תוכן אחד לסקריפט ותוכן אחר לדפדפן, ולא יהיה לכם עותק לבדיקה לאחר מכן. הורידו לקובץ באמצעות curl -fsSL <url> -o install.sh, בצעו לו hash, קראו אותו עם less, ורק אז הריצו אותו. הרגל זה גוזל כעשרים שניות, והוא אותו הרגל שכדאי להתחיל בו ב-שרת VPS חדש בעשר הדקות הראשונות שלו, לפני שמותקן דבר מה נוסף על המכונה.

שמרו רשימת digests עבור רכיבים שהותקנו ידנית

חבילות שהותקנו באמצעות 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 ותקבלו קו בסיס (baseline). נתיבים נשמרים ברשימה בדיוק כפי שהקלדתם אותם, לכן שימוש בנתיבים מוחלטים (absolute paths) יבטיח שהבדיקה תעבוד מכל תיקייה.

היו מודעים לערכו של קו הבסיס הזה. הוא מזהה קובץ שהשתנה. הוא אינו מזהה תוקף שכבר מחזיק בהרשאות root, מכיוון שתוקף כזה יכול לשכתב את inventory.sha256 בקלות שבה שיכתב את הקובץ הבינארי. שמרו את הרשימה מחוץ למכונה אם אתם רוצים שהיא תהיה בעלת משמעות; זהו חלק מהשאלה הרחבה יותר של עד כמה אתם באמת נותנים אמון ב-VPS שלכם ומי עוד יכול להגיע לדיסק שמתחתיו.

FAQ

האם checksum תואם מעיד על כך שההורדה בטוחה?

לא. המשמעות היא שהבתים שבידיך תואמים לערך ה-digest מולו ביצעת את ההשוואה. אם תוקף שולט בדף שפרסם את ה-digest, הוא יפרסם את ה-digest של הקובץ שלו, והבדיקה שלך תציג OK. התאמה היא טענה לעקביות בלבד. טענה לבטיחות דורשת חתימה מאומתת מול מפתח שהושג ממקור אחר, ורק אז ה-digest יורש את רמת האמינות הזו.

מדוע sha256sum -c מציג FAILED open or read?

מכיוון שהקובץ לא נקרא כלל. שורה נפרדת ממש מעל מציינת No such file or directory עם השם שחיפש. השמות בתוך קובץ SHA256SUMS הם יחסיים לתיקייה שבה מריצים את הפקודה; לכן, עליך לעבור לתיקייה המכילה את ההורדה ולהריץ אותה שוב. אם הרשימה כוללת גם קבצים שלא הורדו, יש להוסיף --ignore-missing. פקודת FAILED פשוטה ללא open or read מעידה על מצב הפוך: הקובץ נקרא, אך ה-digest שלו לא תאם.

האם MD5 מספיק טוב לאימות הורדה?

עבור נזק מקרי, כן. העברה קטועה או בלוק פגום בדיסק לא יפיקו במקרה ערך MD5 תואם. מול תוקף, לא. ניתן לייצר שני קבצים שונים עם אותו ערך MD5 מאז שנת 2004, ו-SHA-1 נפרץ בשיטת chosen-prefix collision בשנת 2020. השתמש בשורת ה-SHA-256 כאשר פרויקט מפרסם את שניהם, והתייחס לפרויקט שמספק MD5 בלבד כסימן לתהליך הפצה מיושן.

מה ההבדל בין sha256sum -c לבין gpg --verify?

sha256sum -c מוכיח שקובץ תואם ל-digest. gpg --verify מוכיח שקובץ ה-digest נחתם על ידי בעל מפתח פרטי מסוים. הם עונים על שאלות שונות, לכן יש להריץ את שניהם כאשר פרויקט מציע את שניהם. החתימה הופכת את רשימת ה-digest לאמינה, ורשימת ה-digest הופכת את הקובץ שהורד לאמין.

כיצד בודקים קובץ מול digest שמופיע בדף אינטרנט?

אל תשווה את התווים בעין. שמור את ה-digest ואת שם הקובץ בשורה אחת, מופרדים על ידי שני רווחים, ולאחר מכן הרץ את sha256sum -c מול אותו קובץ וקרא את ה-OK או ה-FAILED שהוא מציג. בניית השורה באמצעות printf '%s %s\n' מונעת טעויות עיצוב שגורמות ל-sha256sum לדחות את הקובץ עם no properly formatted checksum lines found.

#checksums#sha256sum#integrity#supply-chain#security