Verificare un download Linux con sha256sum
Calcola l’hash con sha256sum, verificalo contro SHA256SUMS e modifica un byte: vedrai il controllo fallire e capirai cosa dimostra davvero un checksum.
Verificare un download con un checksum in due minuti
Per verificare un download con un checksum, calcola l’hash del file ricevuto e usa uno strumento per confrontarlo con quello pubblicato dal produttore. sha256sum esegue entrambe le operazioni: senza opzioni stampa un digest, mentre con -c legge un elenco di digest e indica quali file corrispondono. Questa guida esegue l’intera procedura su un file creato appositamente, quindi modifica intenzionalmente quel file per mostrare direttamente il caso di errore.
Tieni presente una sola frase per tutta la procedura. Un checksum indica se i byte in tuo possesso sono quelli da cui è stato prodotto il digest, ma non indica chi lo ha prodotto. Per rispondere a questa seconda domanda servono una firma e una chiave di cui ti fidi. L’ultima parte di questa guida mostra esattamente dove passa il confine tra i due concetti.
Creare un file per fare pratica
Lavorare in una directory temporanea, in modo che nessuno dei comandi riportati modifichi il resto del sistema. Tutti i comandi seguenti fanno parte di GNU coreutils, il set di comandi di base presente su qualsiasi server Ubuntu o Debian, quindi non è necessario installare nulla.
mkdir -p ~/checksum-demo
cd ~/checksum-demo
printf 'the payload of a totally ordinary download\n' > payload.txt
sha256sum payload.txtSi ottiene una riga composta da 64 caratteri esadecimali, due spazi e il nome del file. I 64 caratteri sono il digest del file. Eseguendo di nuovo il comando, la riga è identica, perché l’hashing è deterministico: allo stesso input corrisponde sempre lo stesso output. Se si modifica un carattere del file e si esegue di nuovo il comando, il digest non cambia soltanto di poco. Ha un aspetto completamente diverso, perché l’inversione di un singolo bit dell’input inverte circa la metà dei bit dell’output. Questa proprietà rende una stringa di 64 caratteri un sostituto utilizzabile per un’immagine da 4 GB.
Salva un file SHA256SUMS, quindi verificalo
Un digest visualizzato a schermo non è utile il giorno successivo. Scrivilo in un file, nel formato generato direttamente da sha256sum, così lo strumento potrà leggerlo in seguito.
sha256sum payload.txt > SHA256SUMS
cat SHA256SUMS
sha256sum -c SHA256SUMSsha256sum -c legge ogni riga dell’elenco, calcola l’hash del file indicato in quella riga e confronta i due digest. Un’esecuzione corretta stampa una riga per ogni file:
payload.txt: OKControlla anche lo stato di uscita, perché uno script legge quello e non il testo. Dopo un’esecuzione corretta, echo $? stampa 0. Il nome SHA256SUMS è una convenzione, non una regola, ma le distribuzioni e la maggior parte delle pagine delle release lo utilizzano. Usa quindi anche tu questo nome: chi leggerà il file in seguito saprà cosa contiene senza doverlo aprire.
Modificare un byte e osservare il controllo fallire
Ora danneggia deliberatamente il file. Questo comando scrive un singolo byte all'offset 5 e lascia invariato tutto il resto, quindi il file conserva lunghezza e nome.
printf 'X' | dd of=payload.txt bs=1 seek=5 conv=notrunc status=none
cat payload.txt
sha256sum -c SHA256SUMSconv=notrunc è il flag importante: senza di esso, dd tronca il file nel punto in cui interrompe la scrittura e verificheresti un tipo di danneggiamento molto più evidente. Il controllo ora restituisce:
payload.txt: FAILED
sha256sum: WARNING: 1 computed checksum did NOT matchecho $? restituisce 1. FAILED indica che il file è stato letto e che il suo digest non corrisponde a quello nell'elenco. Ripristina i byte originali e verifica che il controllo restituisca OK:
printf 'the payload of a totally ordinary download\n' > payload.txt
sha256sum -c SHA256SUMSQuesta è l'intera procedura. Una differenza di un solo byte, in qualsiasi punto del file, produce FAILED. Un download interrotto a causa di una connessione persa, un mirror che distribuisce la build di ieri, un proxy che ha riscritto il file durante il transito o un disco che ha restituito un blocco danneggiato: tutti questi casi producono la stessa riga.
Quando l’elenco indica un file che non hai scaricato
Un file SHA256SUMS reale di una distribuzione elenca tutte le immagini rilasciate dal progetto, mentre tu ne hai scaricata una sola. Riproduci qui questa situazione.
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 è un errore diverso da FAILED e confonderli fa perdere tempo. FAILED indica che i byte non sono corretti. FAILED open or read indica che sha256sum non ha trovato affatto il file, quindi non è stato confrontato nulla. In un download reale, la causa più comune è la directory di lavoro, perché i nomi nell’elenco sono relativi alla directory da cui esegui il comando. Spostati nella directory che contiene il file ed esegui di nuovo il comando. Per controllare solo i file effettivamente presenti, usa questa opzione:
sha256sum --ignore-missing -c SHA256SUMS.allIl comando stampa payload.txt: OK e termina con codice 0. Se nessuno dei nomi elencati è presente, --ignore-missing non termina correttamente senza messaggi quando non trova alcun file. Segnala no file was verified e termina con un codice diverso da zero. Questo è il comportamento corretto, perché un controllo superato senza verificare nulla è l’errore che non noteresti mai.
Incollare un digest pubblicato senza leggerlo a occhio
Il confronto a occhio di 64 caratteri esadecimali è il punto in cui questa abitudine diventa inaffidabile. Si controllano i primi quattro caratteri e gli ultimi quattro, poi si considera il valore corrispondente, ma è esattamente il confronto su cui fa affidamento un attaccante determinato. Lasciare il confronto allo strumento è più sicuro. Impostare EXPECTED sul digest copiato dal fornitore, usando EXPECTED= seguito dal valore incollato, quindi costruire la singola riga prevista da -c:
printf '%s %s\n' "$EXPECTED" payload.txt > payload.sha256
cat payload.sha256
sha256sum -c payload.sha256Tra il digest e il nome del file ci sono due spazi. Per questo la stringa di formato ne contiene due. Questa è la struttura scritta da sha256sum e interpretata da -c. Un file che contiene soltanto un digest non è una riga di checksum valida. Il controllo rifiuta quindi l'intero file con no properly formatted checksum lines found invece di tentare di indovinare a quale file ci si riferisca. Alcuni progetti pubblicano invece il formato BSD con tag, SHA256 (payload.txt) = seguito dal digest. GNU coreutils scrive questo formato con sha256sum --tag payload.txt e lo legge nuovamente con -c, quindi è possibile salvare entrambe le strutture.
Quando un controllo produce risultati anomali, esaminare direttamente l'elenco con cat -A SHA256SUMS. Questo comando marca la fine di ogni riga con $ e visualizza i caratteri che altrimenti non sarebbero visibili. Una riga che termina con ^M$ ha probabilmente acquisito un carriage return da un editor Windows. GNU sha256sum ignora questo carattere finale e stampa comunque OK. Un elenco CRLF non è quindi la causa del problema, anche se gli strumenti esterni a coreutils gestiscono questo formato in modo meno tollerante. Normalizzare la copia conservata con tr -d '\r' < SHA256SUMS > SHA256SUMS.clean.
Che cosa dimostra un checksum e che cosa non dimostra?
Un checksum dimostra una sola cosa: i byte presenti sul disco sono i byte da cui è stato prodotto il digest pubblicato. Questo rileva completamente i danni accidentali. Rileva anche un attaccante poco attento che ha sostituito il file su un mirror di download, ma non ha potuto modificare la pagina che pubblicava il digest.
Non dimostra nulla sull'autore. Un digest è un fatto relativo ai byte, non alle persone. Se una stessa pagina distribuisce sia il file sia il digest, chiunque possa modificare l'uno può modificare anche l'altro, e la riga OK indica soltanto che il mirror è coerente con se stesso. Questa è quindi la regola che rende utile eseguire i controlli dei checksum: ottenere il digest da una fonte diversa da quella da cui è stato scaricato il file. Ad esempio, il dominio ufficiale del progetto tramite TLS (transport layer security), mentre l'immagine proviene da un mirror o da un torrent. In questo modo, un attaccante deve controllare due punti invece di uno.
Anche l'algoritmo è importante. SHA-256 (secure hash algorithm, output a 256 bit) non presenta collisioni note ad agosto 2026, per questo i publisher lo utilizzano. MD5 (message digest 5) e SHA-1 non sono più adeguati: dal 2004 è possibile costruire due file diversi con lo stesso digest MD5, e nel 2020 è stata pubblicata una collisione SHA-1 con prefisso scelto. Un file MD5SUMS rileva comunque un download troncato, perché la corruzione casuale non è una collisione costruita ad arte. Non può impedire a qualcuno di tentare di ingannarti. Se un progetto pubblica entrambe le righe, utilizza quella SHA-256.
Quando entrano in gioco le firme
Una firma colma la lacuna lasciata aperta da un digest. Il publisher firma il file dei digest con una chiave privata e tu lo verifichi con la relativa chiave pubblica: gpg --verify SHA256SUMS.asc SHA256SUMS. Se la verifica ha esito positivo, l'elenco dei digest proviene da chi possiede quella chiave. Poi sha256sum -c SHA256SUMS collega il file presente sul disco all'elenco, completando la catena dalla chiave fino ai byte.
Il punto debole si sposta sulla chiave. Scaricare la chiave dalla stessa pagina che ha distribuito il file consegna all'attaccante entrambe le parti. GnuPG lo segnala chiaramente: una prima verifica stampa Good signature insieme a WARNING: This key is not certified with a trusted signature!. Good signature significa che la verifica matematica è corretta. Non significa che la chiave appartenga al progetto che hai in mente. Recupera l'impronta digitale da una seconda fonte, ad esempio la documentazione del progetto su un dominio diverso oppure un pacchetto della distribuzione che include già la chiave, quindi confronta l'impronta completa invece degli ultimi otto caratteri. Questa è la stessa attenzione che merita una chiave privata SSH, per lo stesso motivo: la chiave determina la fiducia e tutto ciò che viene dopo la eredita.
Le build riproducibili portano questa idea un passo oltre. Un digest pubblicato ti vincola comunque a un binario compilato da una singola macchina. Quando la build di un progetto è riproducibile, chiunque può compilare lo stesso codice sorgente e ottenere un output identico a livello di byte. I builder indipendenti possono quindi confermare il digest pubblicato, invece di dover accettare la parola di un unico server. Questo aspetto diventa ogni anno più importante, perché una quantità crescente di codice arriva tramite pipeline automatizzate e patch generate da macchine. Stabilire cosa accettare in una build è una scelta di policy e le policy open source per il codice assistito dall'IA intervengono sulla stessa supply chain dall'altra estremità.
Il gestore dei pacchetti lo fa già per te
Su Debian e Ubuntu, apt esegue automaticamente questa catena a ogni installazione. L'indice dei pacchetti contiene un digest SHA-256 per ogni file .deb. Il file Release contiene i digest di questi file indice e InRelease contiene una firma su Release, verificata rispetto alle chiavi presenti in /usr/share/keyrings e /etc/apt/trusted.gpg.d. Quando la catena non è valida, apt lo segnala: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY quando manca la chiave di un repository di terze parti oppure Hash Sum mismatch quando l'indice scaricato non corrisponde al valore firmato in Release. Di solito, ciò significa che un proxy di caching ha fornito un file obsoleto oppure che il mirror era in fase di sincronizzazione.
Questo è lo standard di riferimento quando la home page di un progetto ti chiede di inoltrare uno script da curl direttamente a una shell tramite pipe. In questo modo non viene verificato alcun byte e non puoi esaminare lo script prima dell'esecuzione. Inoltre, il server può restituire un contenuto a uno script e un contenuto diverso a un browser, senza lasciarti una copia da controllare in seguito. Scarica il contenuto in un file con curl -fsSL <url> -o install.sh, calcolane l'hash, leggilo con less ed eseguilo solo dopo. Questa procedura richiede circa venti secondi ed è la stessa buona pratica da adottare su un VPS appena creato nei suoi primi dieci minuti, prima di installare qualsiasi altro componente sul server.
Mantieni un elenco degli hash per ciò che installi manualmente
I pacchetti installati da apt vengono tracciati. Un binario copiato in /usr/local/bin non viene tracciato e nessun componente del sistema ne monitora la presenza. Un elenco di hash trasforma questa situazione in un controllo eseguibile quando necessario:
printf 'a second file\n' > notes.txt
sha256sum *.txt > inventory.sha256
sha256sum -c --quiet inventory.sha256--quiet non stampa nulla quando tutti i file corrispondono e stampa soltanto le righe che non hanno superato il controllo quando alcuni file differiscono. Il silenzio indica quindi l'esito positivo e echo $? lo conferma con 0. Questo è il formato da usare in un job pianificato. --status va oltre e non stampa alcun output, lasciando disponibile soltanto lo stato di uscita. Applica lo stesso schema ai file reali con sha256sum /usr/local/bin/* > ~/local-bin.sha256 per creare una baseline. I percorsi vengono salvati nell'elenco esattamente come li hai digitati, quindi i percorsi assoluti consentono di eseguire il controllo da qualsiasi directory.
È importante capire il valore effettivo di questa baseline. Rileva un file modificato. Non rileva un attaccante che dispone già dell'account root, perché può riscrivere inventory.sha256 con la stessa facilità con cui ha riscritto il binario. Se vuoi che l'elenco abbia un valore reale, conservalo al di fuori della macchina. Questo rientra nella questione più ampia di quanto ti fidi realmente di un VPS e di chi altro può raggiungere il disco sottostante.
FAQ
Un checksum corrispondente indica che il download è sicuro?
No. Indica che i byte disponibili corrispondono al digest con cui li hai confrontati. Se l'attaccante controlla la pagina che pubblica il digest, pubblica il digest del proprio file e il controllo restituisce OK. Una corrispondenza dimostra solo la coerenza dei dati. Per dimostrare la sicurezza serve una firma verificata con una chiave ottenuta da una fonte diversa. Solo a quel punto il digest eredita tale attendibilità.
Perché sha256sum -c restituisce FAILED open or read?
Perché non ha mai letto il file. Una riga separata, subito sopra, indica No such file or directory con il nome cercato. I nomi contenuti in un file SHA256SUMS sono relativi alla directory da cui esegui il comando. Spostati quindi nella directory che contiene il download ed esegui di nuovo il comando. Se l'elenco include anche file che non hai scaricato, aggiungi --ignore-missing. Un semplice FAILED senza open or read indica la situazione opposta: il file è stato letto, ma il suo digest non corrispondeva.
MD5 è sufficiente per verificare un download?
Sì, per rilevare danni accidentali. Un trasferimento troncato o un blocco danneggiato del disco non produrrà per caso un digest MD5 corrispondente. No, se devi difenderti da un attaccante. Dal 2004 è possibile costruire due file diversi con lo stesso digest MD5 e nel 2020 è stata ottenuta una collisione a prefisso scelto per SHA-1. Usa la riga SHA-256 quando un progetto pubblica entrambi i digest. Considera invece un progetto che usa solo MD5 come indicatore di un processo di rilascio obsoleto.
Qual è la differenza tra sha256sum -c e gpg --verify?
sha256sum -c dimostra che un file corrisponde a un digest. gpg --verify dimostra che un file di digest è stato firmato dal titolare di una determinata chiave privata. Rispondono a domande diverse, quindi eseguili entrambi quando il progetto li mette a disposizione. La firma rende attendibile l'elenco dei digest. L'elenco dei digest rende quindi attendibile il file scaricato.
Come posso verificare un file rispetto a un digest pubblicato su una pagina web?
Non confrontare i caratteri a vista. Salva il digest e il nome del file su un'unica riga, separati da due spazi. Esegui quindi sha256sum -c sul file e leggi OK o FAILED, che il comando restituisce. Creare la riga con printf '%s %s\n' evita gli errori di formattazione che fanno sì che sha256sum rifiuti il file con no properly formatted checksum lines found.