Як перевірити завантаження за 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.
Що підтверджує контрольна сума, а чого вона не підтверджує?
Контрольна сума підтверджує лише одне: байти на вашому диску відповідають байтам, на основі яких обчислено опублікований дайджест. Це повністю виявляє випадкове пошкодження. Це також захищає від необережного зловмисника, який замінив файл на дзеркалі завантаження, але не міг змінити сторінку з опублікованим дайджестом.
Вона нічого не підтверджує щодо авторства. Дайджест є властивістю байтів, а не властивістю людей. Якщо одна сторінка містить і файл, і дайджест, той, хто може змінити одне, може змінити й інше, а ваш рядок OK означає лише, що дзеркало узгоджується саме із собою. Тому діє таке правило, заради якого варто перевіряти контрольні суми: отримуйте дайджест не з того самого місця, що й файл. Наприклад, домен самого проєкту через TLS (transport layer security), якщо образ отримано з дзеркала або через torrent. Тоді зловмиснику потрібно контролювати два місця, а не одне. Це також нічого не говорить про те, що зроблять перевірені байти після запуску. Це окреме питання, яке варто ставити щодо всього, що виконується від вашого імені: від інсталяційного скрипту до плагіна dsh, що працює з дозволами вашого агента.
Алгоритм також має значення. SHA-256 (secure hash algorithm, 256-bit output) станом на August 2026 не має відомих колізій, тому видавці його використовують. MD5 (message digest 5) і SHA-1 не забезпечують належного захисту: два різні файли з однаковим дайджестом MD5 можна було створювати ще з 2004, а колізію SHA-1 із вибраним префіксом опубліковано у 2020. Файл MD5SUMS все одно виявляє неповне завантаження, оскільки випадкове пошкодження не є навмисно створеною колізією. Він не може зупинити того, хто намагається вас обманути. Якщо проєкт публікує обидва варіанти, використовуйте рядок SHA-256.
Коли підпис стає основним захистом
Підпис усуває прогалину, яку залишає digest. Видавець підписує файл із digest за допомогою приватного ключа, а ви перевіряєте його публічним ключем: gpg --verify SHA256SUMS.asc SHA256SUMS. Якщо перевірка успішна, список digest надійшов від того, хто володіє цим ключем. Потім 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, замість того щоб просто довіряти одному серверу. Це стає важливішим щороку, оскільки дедалі більше коду надходить через автоматизовані 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. Зазвичай це означає, що кешувальний проксі повернув застарілий файл або ви звернулися до дзеркала під час синхронізації.
Саме з цим стандартом слід порівнювати інструкції на головній сторінці проєкту, які пропонують передати скрипт із curl безпосередньо в оболонку. Байти ніхто не перевіряє, і ви їх не бачите. Сервер також може повернути скрипту один вміст, а браузеру — інший, і після цього у вас не залишиться копії для перевірки. Завантажте файл за допомогою curl -fsSL <url> -o install.sh, обчисліть його хеш, прочитайте його за допомогою less і лише потім запустіть. Це займає приблизно двадцять секунд. Таку звичку варто сформувати під час першого налаштування нового VPS у перші десять хвилин, ще до встановлення будь-чого іншого на сервер.
Ведіть список digest-значень для всього, що встановлюєте вручну
Пакети, встановлені через apt, відстежуються. Бінарний файл, скопійований у /usr/local/bin, не відстежується, і в системі немає процесу, який контролював би його. Список digest-значень дає змогу перевіряти такі файли за потреби:
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.