Linuxでsha256sumを使いダウンロードを検証する方法
Linuxでsha256sumを使い、SHA256SUMSファイルとダウンロードを照合する方法を解説します。1バイト変更で検証が失敗する実例から、チェックサムが証明できる範囲も確認できます。
チェックサムでダウンロードを2分で検証する
チェックサムでダウンロードを検証するには、受け取ったファイルをハッシュ化し、そのハッシュを公開者が示した値とツールで比較します。sha256sum はこの両方を実行できます。単独ではダイジェストを出力し、-c を指定するとダイジェストの一覧を読み込み、一致するファイルを報告します。このガイドでは、作成したファイルを使って一連の手順を実行します。その後、意図的にファイルを変更し、失敗が発生する様子を確認します。
最初から最後まで、次の点を覚えておいてください。チェックサムで確認できるのは、手元のバイト列がそのダイジェストを生成したバイト列と同じかどうかです。そのダイジェストを誰が生成したかは確認できません。後者を確認するには、信頼できる署名と暗号鍵が必要です。このガイドの最後では、この2つの違いを明確に示します。
練習用のファイルを作成する
スクラッチディレクトリで作業し、この手順によってシステムの他の部分に影響が及ばないようにします。以下のコマンドはすべて GNU coreutils に含まれています。Ubuntu または Debian サーバーに標準で存在する基本コマンド群のため、インストールは不要です。
mkdir -p ~/checksum-demo
cd ~/checksum-demo
printf 'the payload of a totally ordinary download\n' > payload.txt
sha256sum payload.txt1 行の出力が得られます。64 個の16進数文字、2 個のスペース、ファイル名の順です。この64文字がファイルのダイジェストです。同じコマンドをもう一度実行すると、同じ行が出力されます。ハッシュは決定論的であり、同じ入力からは常に同じ出力が得られるためです。ファイルの1文字を変更して再度実行すると、ダイジェストが少しだけ変わることはありません。完全に異なる値になります。入力の1ビットを反転すると、出力の約半分のビットが反転するためです。この性質により、64文字の文字列を4 GBのイメージの代用として使用できます。
SHA256SUMS ファイルを保存して検証する
画面に表示されたダイジェストは、翌日には役に立ちません。sha256sum 自体が出力する形式でファイルに書き込み、後でツールが読み込めるようにします。
sha256sum payload.txt > SHA256SUMS
cat SHA256SUMS
sha256sum -c SHA256SUMSsha256sum -c はリストの各行を読み取り、その行に記載されたファイルをハッシュ化して、2 つのダイジェストを比較します。正常に完了すると、ファイルごとに 1 行が表示されます。
payload.txt: OK終了ステータスも確認してください。スクリプトはテキストではなく終了ステータスを読み取るためです。正常に完了すると、echo $? は 0 を出力します。SHA256SUMS という名前は規則ではなく慣例ですが、ディストリビューションや大半のリリースページで使われています。そのため同じ名前を使うと、次の担当者はファイルを開かなくても内容を把握できます。
1 バイトを変更し、チェックが失敗することを確認する
ここで、意図的にファイルを壊します。次のコマンドは offset 5 の 1 バイトだけを書き換え、それ以外は変更しません。そのため、ファイルの長さと名前は維持されます。
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 matchecho $? は 1 を出力します。FAILED は、ファイルが読み込まれ、そのダイジェストがリスト内の値と一致しなかったことを示します。元のバイトを戻し、チェック結果が OK に戻ることを確認します。
printf 'the payload of a totally ordinary download\n' > payload.txt
sha256sum -c SHA256SUMSこれが基本的な手順のすべてです。ファイル内のどこであっても、1 バイト違えば FAILED になります。接続切断で途中までしか完了しなかったダウンロード、前日のビルドを提供するミラー、転送中にファイルを書き換えたプロキシ、読み取り時に不良ブロックを返したディスク。いずれの場合も、同じ行に該当します。
リストにダウンロードしていないファイルが記載されている場合
実際のディストリビューションの SHA256SUMS ファイルには、プロジェクトがリリースするすべてのイメージが記載されており、そのうちの1つをダウンロードします。ここでは、その状況を再現します。
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.allpayload.txt: OKと出力され、0 で終了します。リストに記載された名前が1つも存在しない場合、--ignore-missingはファイルが0個でも成功として終了しません。no file was verifiedと報告して、0 以外のステータスで終了します。これは望ましい動作です。何も確認していないのに成功することは、最も気付きにくい失敗だからです。
目視せずに公開元のダイジェストを貼り付ける
64 文字の16進数を目視で比較すると、この習慣の問題がはっきりします。先頭4文字と末尾4文字だけを確認して一致したと判断する人がいますが、攻撃者はまさにその比較方法を狙います。比較はツールに任せてください。公開元からコピーしたダイジェストを EXPECTED に設定します。EXPECTED= に続けて貼り付けた値を指定し、-c が想定する1行を作成します。
printf '%s %s\n' "$EXPECTED" payload.txt > payload.sha256
cat payload.sha256
sha256sum -c payload.sha256ダイジェストとファイル名の間には2つの空白があります。そのため、フォーマット文字列にも2つの空白が含まれます。これは 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 で正規化してください。
チェックサムで証明できること、できないこと
チェックサムで証明できるのは1つです。ディスク上のバイト列が、公開されたダイジェストを生成したバイト列と同一であることです。これにより、偶発的な破損は完全に検出できます。ダイジェストを公開したページにはアクセスできない不注意な攻撃者が、ダウンロードミラー上のファイルだけを差し替えた場合も検出できます。
作成者については何も証明できません。ダイジェストが示すのはバイト列に関する事実であり、人に関する事実ではありません。同じページでファイルとダイジェストの両方を提供している場合、一方を変更できる人はもう一方も変更できます。そのため、OK 行が示すのは、ミラーが自分自身と一致していることだけです。そこで、チェックサムを実行する価値を生むルールがあります。ファイルを取得した場所とは別の場所からダイジェストを取得してください。たとえば、イメージをミラーまたは torrent から取得し、プロジェクト独自のドメインから TLS (transport layer security) 経由でダイジェストを取得します。これで、攻撃者は1か所ではなく2か所を制御する必要があります。
アルゴリズムも重要です。SHA-256 (secure hash algorithm、256-bit output) では、2026年8月時点で既知の衝突がないため、公開者はこれを使用しています。MD5 (message digest 5) と SHA-1 は信頼できません。同じ 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 は、暗号学的な検証が成立したことを意味します。ただし、その鍵が想定しているプロジェクトのものだという意味ではありません。別ドメインにあるプロジェクトのドキュメントや、その鍵を同梱済みのディストリビューションパッケージなど、別の情報源からフィンガープリントを取得し、末尾 8 文字ではなく完全なフィンガープリントを比較してください。これは SSH 秘密鍵に払うべき注意と同じ です。理由も同じです。鍵が信頼の判断を決め、その後のすべての検証が鍵を引き継ぐためです。
再現可能ビルドでは、この考え方をさらに進めます。公開されたダイジェストだけでは、1 台のマシンがビルドしたバイナリを信頼することになります。プロジェクトのビルドが再現可能であれば、誰でも同じソースコードをコンパイルしてバイト単位で同一の出力を得られます。そのため、独立したビルド実行者が公開されたダイジェストを確認でき、1 台のサーバーの説明をそのまま信頼する必要がありません。自動化されたパイプラインや機械生成のパッチを通じて届くコードが年々増えているため、これは重要性を増しています。ビルドに受け入れる対象を決めることはポリシーの問題です。AI 支援コードに関するオープンソースポリシーも、反対側から同じソフトウェアサプライチェーンに取り組みます。
パッケージマネージャーはすでにこれを自動で行います
Debian と Ubuntu では、apt が要求しなくても、インストールのたびにこの検証チェーンを実行します。パッケージインデックスには、各 .deb ファイルの SHA-256 ダイジェストが含まれています。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、取得したインデックスが署名済みの Release と一致しない場合は Hash Sum mismatch です。後者は通常、キャッシュプロキシが古いファイルを返したか、ミラーが同期中のタイミングで取得したことを意味します。
プロジェクトのホームページが curl からスクリプトを直接 shell にパイプするよう指示している場合は、これを基準に判断してください。その方法ではバイト列が検証されず、内容も確認できません。サーバーは、スクリプトにはある内容を返し、ブラウザーには別の内容を返すこともできます。後から調査できるコピーも残りません。curl -fsSL <url> -o install.sh でファイルにダウンロードし、ハッシュを計算し、less で内容を読み、その後でのみ実行してください。この習慣にかかる時間は約 20 秒です。何もインストールしていない 新しい VPS の最初の 10 分 に始める価値がある習慣でもあります。
手作業でインストールしたファイルのダイジェスト一覧を保持する
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 を追加します。open or read を伴わない単独の FAILED は、逆の状況を示します。ファイルは読み込まれましたが、ダイジェストが一致しませんでした。
ダウンロードの検証に MD5 を使っても十分ですか?
偶発的な破損の検出には十分です。転送の途中で切れたファイルや、壊れたディスクブロックから、偶然一致する MD5 ダイジェストが生成されることはありません。攻撃者への対策としては不十分です。MD5 ダイジェストが同じ異なるファイルは、2004 年以降、作成可能になっています。また、SHA-1 も 2020 年に選択プレフィックス衝突が実証されました。プロジェクトが SHA-256 と MD5 の両方を公開している場合は、SHA-256 の行を使用してください。MD5 しか提供しないプロジェクトは、古いリリース手順を使っている兆候と考えてください。
sha256sum -c と gpg --verify の違いは何ですか?
sha256sum -c は、ファイルがダイジェストと一致することを証明します。gpg --verify は、ダイジェストファイルが特定の秘密鍵の保有者によって署名されたことを証明します。異なる質問に答えるものなので、プロジェクトが両方を提供している場合は、両方を実行してください。署名によってダイジェストのリストが信頼できるものになり、そのダイジェストのリストによって、ダウンロードしたファイルも信頼できるものになります。
Web ページに表示されたダイジェストで、1 つのファイルを確認するにはどうすればよいですか?
文字列を目視で比較しないでください。ダイジェストとファイル名を、2 個のスペースで区切って 1 行に保存します。その後、sha256sum -c をそのファイルに対して実行し、出力される OK または FAILED を確認します。printf '%s %s\n' で行を作成すると、sha256sum が no properly formatted checksum lines found でファイルを拒否する原因となる書式ミスを避けられます。