Як перевірити завантаження за SHA256 у Linux
Дізнайтеся, як sha256sum перевіряє файл за SHA256SUMS, і побачте точну помилку після зміни одного байта. Контрольна сума не підтверджує джерело файла.
Перевірте завантажений файл за контрольною сумою за дві хвилини
Щоб перевірити завантажений файл за контрольною сумою, обчисліть хеш отриманого файла та передайте інструменту завдання порівняти цей хеш із хешем, опублікованим видавцем. 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 символи є дайджестом файлу. Якщо виконати команду ще раз, рядок буде ідентичним, оскільки хешування є детермінованим: однакові вхідні дані завжди дають однаковий результат. Змініть у файлі один символ і виконайте команду ще раз — дайджест не зміниться лише незначно. Він виглядатиме повністю інакше, оскільки зміна одного вхідного біта змінює приблизно половину вихідних бітів. Саме тому 64-символьний рядок може надійно представляти образ розміром 4 GB.
Збережіть файл SHA256SUMS, а потім перевірте його
Хеш на екрані наступного дня вже не допоможе. Запишіть його у файл у форматі, який формує сама sha256sum, щоб пізніше інструмент міг зчитати його назад.
sha256sum payload.txt > SHA256SUMS
cat SHA256SUMS
sha256sum -c SHA256SUMSsha256sum -c читає кожен рядок списку, обчислює хеш файлу, указаного в цьому рядку, і порівнює два дайджести. Якщо перевірка пройшла успішно, для кожного файлу виводиться один рядок:
payload.txt: OKТакож перевірте код завершення, оскільки скрипт читає саме його, а не текстовий вивід. Після успішного виконання echo $? виводить 0. Назва SHA256SUMS є усталеною, а не обов’язковою, але її використовують дистрибутиви та більшість сторінок із релізами. Тому використовуйте її також: наступна людина зрозуміє вміст файлу, не відкриваючи його.
Змініть один байт і перевірте, як перевірка завершується помилкою
Тепер навмисно пошкодьте файл. Ця команда записує один байт за зміщенням 5 і не змінює решту даних, тому файл зберігає свою довжину та ім’я.
printf 'X' | dd of=payload.txt bs=1 seek=5 conv=notrunc status=none
cat payload.txt
sha256sum -c SHA256SUMSconv=notrunc — це важливий прапорець: без нього dd обрізає файл у місці, де припиняє запис, і ви перевіряли б набагато очевидніший тип пошкодження. Тепер перевірка виводить:
payload.txt: FAILED
sha256sum: WARNING: 1 computed checksum did NOT matchecho $? виводить 1. FAILED означає, що файл прочитано, але його дайджест не збігається зі значенням у списку. Відновіть початкові байти та переконайтеся, що перевірка знову повертає OK:
printf 'the payload of a totally ordinary download\n' > payload.txt
sha256sum -c SHA256SUMSУ цьому полягає весь підхід. Відмінність навіть одного байта в будь-якому місці файлу дає FAILED. Незавершене завантаження через розірване з’єднання, дзеркало зі збіркою за вчорашній день, проксі, який змінив файл під час передавання, або диск, що повернув пошкоджений блок, — усі ці випадки призводять до того самого рядка.
Коли список містить ім’я файлу, який ви не завантажували
Справжній файл SHA256SUMS від дистрибутива містить список усіх образів, які випускає проєкт, а ви завантажили лише один із них. Відтворіть цю ситуацію тут.
printf 'a second file\n' > notes.txt
sha256sum payload.txt notes.txt > SHA256SUMS.all
rm notes.txt
sha256sum -c SHA256SUMS.allpayload.txt: OK
sha256sum: notes.txt: No such file or directory
notes.txt: FAILED open or read
sha256sum: WARNING: 1 listed file could not be readFAILED 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. Файл, що містить лише дайджест без назви файлу, не є рядком контрольної суми. Тому перевірка відхиляє весь файл із no properly formatted checksum lines found, а не намагається визначити, який файл ви мали на увазі. Деякі проєкти натомість публікують формат із тегом BSD: SHA256 (payload.txt) = , після якого вказано дайджест. GNU coreutils записує такий формат за допомогою sha256sum --tag payload.txt і зчитує його за допомогою -c, тому для збереження можна використовувати будь-який із цих форматів.
Якщо перевірка працює неочікувано, перегляньте сам список за допомогою cat -A SHA256SUMS. Ця команда позначає кінець кожного рядка символом $ і показує символи, яких інакше не видно. Рядок, що закінчується на ^M$, отримав символ повернення каретки з редактора Windows. GNU sha256sum ігнорує цей кінцевий символ і все одно виводить OK. Отже, список із завершеннями рядків CRLF не є причиною помилки перевірки, хоча інші інструменти, не належні до coreutils, можуть обробляти такий формат суворіше. Нормалізуйте збережену копію за допомогою tr -d '\r' < SHA256SUMS > SHA256SUMS.clean.
Що підтверджує checksum, а чого він не підтверджує?
Checksum підтверджує лише одне: байти на вашому диску відповідають байтам, для яких обчислено опублікований digest. Це повністю виявляє випадкове пошкодження. Це також захищає від недбалого зловмисника, який підмінив файл на дзеркалі завантаження, але не міг змінити сторінку, де опубліковано digest.
Checksum нічого не підтверджує щодо авторства. Digest — це властивість байтів, а не людей. Якщо одна сторінка містить і файл, і digest, той, хто може змінити одне, може змінити й інше. У такому разі ваш рядок OK означає лише, що дзеркало узгоджується саме із собою. Тому застосовуйте правило, завдяки якому перевірка checksum має сенс: отримуйте digest не з того самого місця, що й файл. Наприклад, домен самого проєкту через TLS (transport layer security), а образ — із дзеркала або через torrent. Тоді зловмиснику потрібно контролювати два місця, а не одне.
Алгоритм також має значення. SHA-256 (secure hash algorithm, 256-bit output) не має відомих колізій станом на August 2026, тому видавці його використовують. MD5 (message digest 5) і SHA-1 не забезпечують достатнього захисту: два різні файли з однаковим digest MD5 можна було створити ще з 2004, а колізію SHA-1 із вибраним префіксом опубліковано у 2020. Файл MD5SUMS все одно виявить неповне завантаження, оскільки випадкове пошкодження не є цілеспрямованою колізією. Але він не захистить від того, хто навмисно намагається вас обдурити. Якщо проєкт публікує обидва варіанти, використовуйте рядок SHA-256.
Коли на зміну приходять підписи
Підпис усуває прогалину, яку залишає дайджест. Видавець підписує файл із дайджестами приватним ключем, а ви перевіряєте його відкритим ключем: gpg --verify SHA256SUMS.asc SHA256SUMS. Якщо перевірка успішна, список дайджестів надійшов від того, хто володіє цим ключем. Потім sha256sum -c SHA256SUMS пов’язує файл на вашому диску зі списком, і ланцюжок довіри простягається від ключа до самих байтів.
Слабке місце тепер зосереджується на ключі. Якщо отримати ключ із тієї самої сторінки, з якої завантажено файл, зловмисник отримує обидві складові. GnuPG прямо повідомляє про це, і під час першої перевірки виводить Good signature разом із WARNING: This key is not certified with a trusted signature!. Good signature означає, що математична перевірка успішна. Це не означає, що ключ належить саме тому проєкту, який ви маєте на увазі. Отримайте відбиток із другого джерела, наприклад із документації проєкту на іншому домені або з пакета дистрибутива, у якому цей ключ уже постачається, і порівняйте повний відбиток, а не лише останні вісім символів. Це та сама обережність, якої потребує приватний ключ SSH, з тієї самої причини: ключ визначає довіру, і всі наступні компоненти успадковують її.
Відтворювані збірки розвивають цю ідею ще на крок. Опублікований дайджест усе одно прив’язує вас до бінарного файлу, який зібрала одна машина. Якщо збірка проєкту відтворювана, будь-хто може скомпілювати той самий вихідний код і отримати побайтно ідентичний результат. Тоді незалежні збирачі можуть підтвердити опублікований дайджест, замість того щоб покладатися на слова одного сервера. Це стає дедалі важливішим, оскільки щороку більше коду надходить через автоматизовані pipeline та патчі, написані машинами. Визначення того, що можна додавати до збірки, є питанням політики, а політики open source для коду за допомогою AI працюють із тим самим ланцюгом постачання, але з іншого боку.
Це вже робить ваш менеджер пакетів
У 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 передав застарілий файл або ви звернулися до дзеркала під час синхронізації.
Саме з цим стандартом слід порівнювати інструкції на головній сторінці проєкту, де пропонується передати скрипт із curl безпосередньо в shell. У такому разі байти не перевіряються, і ви їх не бачите. Сервер також може повернути скрипту один вміст, а браузеру — інший, і після цього у вас не залишиться копії для перевірки. Завантажте файл за допомогою curl -fsSL <url> -o install.sh, обчисліть його хеш, прочитайте його за допомогою less і лише потім запустіть. Ця звичка займає приблизно двадцять секунд. Її варто сформувати під час налаштування нового VPS у перші десять хвилин, перш ніж встановлювати на сервер будь-що інше.
Ведіть список дайджестів для всього, що встановлюєте вручну
Пакети, встановлені через apt, відстежуються. Бінарний файл, який ви скопіювали в /usr/local/bin, не відстежується, і в системі немає процесу, який би його контролював. Список дайджестів дає змогу перевіряти такі файли за потреби:
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
Чи означає відповідність контрольної суми, що завантаження безпечне?
Ні. Це означає, що отримані байти відповідають дайджесту, з яким ви їх порівняли. Якщо зловмисник контролює сторінку, де опубліковано дайджест, він публікує дайджест власного файлу, і перевірка виводить OK. Відповідність підтверджує узгодженість. Для підтвердження безпеки потрібен підпис, перевірений за ключем, отриманим з іншого джерела. Лише після цього довіра до дайджесту успадковується від ключа.
Чому sha256sum -c виводить FAILED open or read?
Тому що команда не прочитала файл. Окремий рядок безпосередньо перед цим повідомляє No such file or directory і містить назву, яку шукала команда. Назви у файлі SHA256SUMS є відносними до каталогу, у якому ви запускаєте команду. Перейдіть до каталогу із завантаженим файлом і запустіть команду ще раз. Якщо список також містить назви файлів, які ви не завантажували, додайте --ignore-missing. Просте FAILED без open or read означає протилежну ситуацію: файл було прочитано, але його дайджест не відповів очікуваному.
Чи достатньо MD5 для перевірки завантаження?
Так, для виявлення випадкового пошкодження. Обірване передавання або пошкоджений блок диска випадково не дадуть відповідного дайджесту MD5. Проти зловмисника — ні. Два різні файли з однаковим дайджестом MD5 можна було створювати ще з 2004 року, а у 2020 році для SHA-1 було продемонстровано колізію з вибраним префіксом. Використовуйте рядок 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.