Verificar downloads com checksum no Linux
Use sha256sum para comparar um ficheiro com SHA256SUMS, altere um byte e veja a falha exata que mostra o que um checksum realmente comprova.
Verificar um download com um checksum em dois minutos
Para verificar um download com um checksum, calcule o hash do ficheiro recebido e deixe uma ferramenta comparar esse hash com o que o publicador apresentou. sha256sum faz as duas partes do trabalho: por si só, apresenta um digest e, com -c, lê uma lista de digests e indica quais ficheiros correspondem. Este guia percorre todo o processo com um ficheiro criado por si e depois altera esse ficheiro de propósito, para que observe a falha em vez de apenas ler sobre ela.
Tenha uma frase em mente durante todo o processo. Um checksum indica se os bytes que possui são os bytes que produziram o digest, mas não indica quem os produziu. Essa segunda questão requer uma assinatura e uma chave em que confie. A última parte deste guia mostra exatamente onde fica a distinção entre os dois.
Criar um ficheiro para praticar
Trabalhe num diretório temporário para que nada do que fizer aqui afete o resto do sistema. Todos os comandos abaixo fazem parte do GNU coreutils, o conjunto base de comandos presente em qualquer servidor Ubuntu ou Debian. Por isso, não é necessário instalar nada.
mkdir -p ~/checksum-demo
cd ~/checksum-demo
printf 'the payload of a totally ordinary download\n' > payload.txt
sha256sum payload.txtÉ apresentada uma linha: 64 caracteres hexadecimais, dois espaços e o nome do ficheiro. Esses 64 caracteres são o digest do ficheiro. Execute o comando novamente e a linha será idêntica, porque o hashing é determinístico: a mesma entrada produz sempre a mesma saída. Altere um carácter do ficheiro e execute o comando outra vez. O digest não muda ligeiramente. Fica completamente diferente, porque inverter um bit da entrada inverte aproximadamente metade dos bits da saída. Esta propriedade permite usar uma string de 64 caracteres como representação de uma imagem de 4 GB.
Guardar um ficheiro SHA256SUMS e verificá-lo
Um digest apresentado no ecrã não serve de nada no dia seguinte. Grave-o num ficheiro, no formato que o próprio sha256sum produz, para que a ferramenta o possa ler mais tarde.
sha256sum payload.txt > SHA256SUMS
cat SHA256SUMS
sha256sum -c SHA256SUMSsha256sum -c lê cada linha da lista, calcula o hash do ficheiro indicado nessa linha e compara os dois digests. Uma execução correta apresenta uma linha por ficheiro:
payload.txt: OKVerifique também o estado de saída, porque um script lê esse valor e não o texto. echo $? apresenta 0 depois de uma execução correta. O nome SHA256SUMS é uma convenção, não uma regra, mas as distribuições e a maioria das páginas de releases usam-no. Use-o também, para que a pessoa seguinte saiba o que o ficheiro contém sem o abrir.
Altere um byte e observe a falha da verificação
Agora danifique o ficheiro de propósito. Isto escreve um único byte no deslocamento 5 e deixa todo o resto inalterado, pelo que o ficheiro mantém o tamanho e o nome.
printf 'X' | dd of=payload.txt bs=1 seek=5 conv=notrunc status=none
cat payload.txt
sha256sum -c SHA256SUMSconv=notrunc é a opção relevante: sem ela, dd trunca o ficheiro no ponto em que deixa de escrever, e estaria a testar um tipo de dano muito mais evidente. A verificação apresenta agora:
payload.txt: FAILED
sha256sum: WARNING: 1 computed checksum did NOT matchecho $? apresenta 1. FAILED significa que o ficheiro foi lido e que o seu resumo criptográfico não corresponde ao que está na lista. Restaure os bytes originais e confirme que a verificação volta a apresentar OK:
printf 'the payload of a totally ordinary download\n' > payload.txt
sha256sum -c SHA256SUMSEsse é todo o procedimento. Uma diferença de um byte, em qualquer ponto do ficheiro, produz FAILED. Uma transferência interrompida por uma ligação perdida, um mirror que serve a compilação do dia anterior, um proxy que reescreveu o ficheiro durante o trânsito ou um disco que devolveu um bloco inválido: todos estes casos aparecem na mesma linha.
Quando a lista referencia um ficheiro que não descarregou
Um ficheiro SHA256SUMS real de uma distribuição lista todas as imagens que o projeto disponibiliza, mas você descarregou apenas uma delas. Reproduza essa situação aqui.
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 indica uma falha diferente de FAILED, e confundir as duas faz perder tempo. FAILED significa que os bytes estão incorretos. FAILED open or read significa que sha256sum nem sequer encontrou o ficheiro, pelo que nada foi comparado. Numa descarga real, a causa habitual é o diretório de trabalho, porque os nomes da lista são relativos ao diretório onde executa o comando. Mude para o diretório que contém o ficheiro e execute o comando novamente. Para verificar apenas os ficheiros que realmente tem, peça isso:
sha256sum --ignore-missing -c SHA256SUMS.allIsto imprime payload.txt: OK e termina com o código 0. Se nenhum dos nomes listados estiver presente, --ignore-missing não termina silenciosamente com zero ficheiros. Indica que no file was verified e termina com um código diferente de zero. Esse é o comportamento pretendido, porque uma validação que não verificou nada seria uma falha que nunca detetaria.
Cole um digest publicado sem o ler visualmente
Comparar 64 caracteres hexadecimais visualmente é o ponto em que este hábito falha. As pessoas verificam os primeiros quatro caracteres e os últimos quatro e consideram que há correspondência. Essa é exatamente a comparação que um atacante determinado espera que seja feita. Deixe a ferramenta fazer a comparação. Defina EXPECTED como o digest copiado do publicador, usando EXPECTED= seguido do valor colado. Em seguida, crie a linha única que -c espera:
printf '%s %s\n' "$EXPECTED" payload.txt > payload.sha256
cat payload.sha256
sha256sum -c payload.sha256Há dois espaços entre o digest e o nome do ficheiro. Por isso, a string de formato contém dois espaços. Esse é o formato que sha256sum escreve e que -c analisa. Um ficheiro que contenha apenas um digest não constitui uma linha de checksum. Por isso, a verificação rejeita o ficheiro inteiro com no properly formatted checksum lines found, em vez de tentar adivinhar a que ficheiro se referia. Alguns projetos publicam o formato BSD com a etiqueta do ficheiro, SHA256 (payload.txt) = seguida do digest. GNU coreutils escreve esse formato com sha256sum --tag payload.txt e lê-o novamente com -c. Pode guardar qualquer um dos dois formatos.
Quando uma verificação tem um comportamento inesperado, examine a própria lista com cat -A SHA256SUMS. Esse comando marca o fim de cada linha com $ e mostra caracteres que, de outra forma, não seriam visíveis. Uma linha terminada em ^M$ recebeu um carriage return de um editor Windows. GNU sha256sum ignora esse caractere final e continua a mostrar OK. Portanto, uma lista CRLF não é o que está a interromper a verificação, embora ferramentas fora do coreutils sejam menos tolerantes. Normalize a cópia que guardar com tr -d '\r' < SHA256SUMS > SHA256SUMS.clean.
O que uma soma de verificação prova e o que não prova?
Uma soma de verificação prova uma coisa: os bytes no seu disco são os bytes que produziram o resumo publicado. Isto cobre completamente danos acidentais. Também cobre um atacante descuidado que substituiu o ficheiro num mirror de download, mas não conseguiu alterar a página que publicou o resumo.
Não prova nada sobre autoria. Um resumo é um facto sobre bytes, não sobre pessoas. Se uma página fornece tanto o ficheiro como o resumo, quem conseguir alterar um também consegue alterar o outro, e a sua linha OK significa apenas que o mirror está de acordo consigo próprio. Por isso, esta é a regra que torna útil executar somas de verificação: obtenha o resumo de um local diferente daquele de onde obteve o ficheiro. Por exemplo, o domínio oficial do projeto através de TLS (transport layer security), enquanto a imagem veio de um mirror ou de um torrent. Assim, um atacante tem de controlar dois locais em vez de um.
O algoritmo também importa. SHA-256 (secure hash algorithm, saída de 256 bits) não tem nenhuma colisão conhecida em agosto de 2026, razão pela qual os publicadores o utilizam. MD5 (message digest 5) e SHA-1 não são suficientemente seguros: desde 2004 é possível construir dois ficheiros diferentes com o mesmo resumo MD5, e uma colisão SHA-1 com prefixo escolhido foi publicada em 2020. Um ficheiro MD5SUMS ainda deteta um download truncado, porque a corrupção aleatória não é uma colisão criada de forma intencional. Não consegue impedir alguém que esteja a tentar enganá-lo. Quando um projeto publica ambos, utilize a linha SHA-256.
Quando as assinaturas assumem o controlo
Uma assinatura fecha a lacuna deixada por um digest. O editor assina o ficheiro de digest com uma chave privada, e você verifica-o com a chave pública correspondente: gpg --verify SHA256SUMS.asc SHA256SUMS. Se a verificação for bem-sucedida, a lista de digests veio de quem possui essa chave. Depois, sha256sum -c SHA256SUMS associa o ficheiro no seu disco à lista, e a cadeia estende-se desde a chave até aos bytes.
O ponto fraco passa a ser a chave. Obter a chave na mesma página que disponibilizou o ficheiro entrega novamente ambas as partes ao atacante. O GnuPG é explícito sobre isto, e uma primeira verificação apresenta Good signature juntamente com WARNING: This key is not certified with a trusted signature!. Good signature significa que a matemática está correta. Não significa que a chave pertença ao projeto que tem em mente. Obtenha a impressão digital a partir de uma segunda fonte, como a documentação do projeto noutro domínio ou um pacote de distribuição que já inclua a chave, e compare a impressão digital completa em vez dos últimos oito caracteres. Este é o mesmo cuidado que uma chave privada SSH exige, pelo mesmo motivo: a chave determina a confiança, e tudo o que vem depois herda essa decisão.
As compilações reprodutíveis levam esta ideia um passo mais longe. Um digest publicado ainda o associa a um binário criado por uma única máquina. Quando a compilação de um projeto é reprodutível, qualquer pessoa pode compilar o mesmo código-fonte e obter uma saída idêntica byte a byte. Assim, compiladores independentes podem confirmar o digest publicado, em vez de lhe pedir que confie na palavra de um único servidor. Isto torna-se mais importante todos os anos, à medida que mais código chega através de pipelines automatizados e patches escritos por máquinas. Decidir o que aceita numa compilação é uma questão de política, e as políticas de código aberto para código assistido por IA atuam na mesma cadeia de fornecimento, mas a partir da outra extremidade.
O seu gestor de pacotes já faz isto por si
No Debian e no Ubuntu, apt executa esta cadeia em todas as instalações sem pedir confirmação. O índice de pacotes contém um resumo SHA-256 para cada ficheiro .deb. O ficheiro Release contém os resumos desses ficheiros de índice, e InRelease contém uma assinatura sobre Release, validada com base nas chaves em /usr/share/keyrings e /etc/apt/trusted.gpg.d. Quando a cadeia falha, o apt informa-o: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY quando falta a chave de um repositório de terceiros, ou Hash Sum mismatch quando o índice obtido não corresponde ao Release assinado. Normalmente, isto significa que um proxy de cache forneceu um ficheiro desatualizado ou que o mirror estava a meio de uma sincronização.
Esse é o padrão de comparação quando a página inicial de um projeto indica que deve encaminhar um script de curl diretamente para uma shell. Nenhum mecanismo verifica os bytes e nunca os vê. O servidor também pode devolver uma coisa a um script e outra a um browser, e depois não terá uma cópia para inspecionar. Transfira o ficheiro com curl -fsSL <url> -o install.sh, calcule o hash, leia-o com less e só depois o execute. Este hábito demora cerca de vinte segundos e é igualmente importante adotá-lo num VPS acabado de criar, nos seus primeiros dez minutos, antes de instalar qualquer outra coisa no servidor.
Mantenha uma lista de digests do que instalar manualmente
Os pacotes instalados por apt são monitorizados. Um binário copiado para /usr/local/bin não é, e nenhum componente do sistema o monitoriza. Uma lista de digests transforma isso em algo que pode verificar quando necessário:
printf 'a second file\n' > notes.txt
sha256sum *.txt > inventory.sha256
sha256sum -c --quiet inventory.sha256--quiet não imprime nada quando todos os ficheiros correspondem e imprime apenas as linhas que falharam quando alguns não correspondem. Portanto, o silêncio indica sucesso e echo $? confirma-o com 0. Este é o formato a utilizar numa tarefa agendada. --status vai mais longe e não imprime absolutamente nada, deixando apenas o estado de saída. Aponte o mesmo padrão para ficheiros reais com sha256sum /usr/local/bin/* > ~/local-bin.sha256 para criar uma baseline. Os caminhos são armazenados na lista exatamente como foram escritos, por isso os caminhos absolutos permitem executar a verificação a partir de qualquer diretório.
Tenha em conta o valor real dessa baseline. Ela deteta um ficheiro alterado. Não deteta um atacante que já tenha acesso a root, porque esse atacante pode reescrever inventory.sha256 com a mesma facilidade com que reescreveu o binário. Mantenha a lista fora da máquina se quiser que ela tenha algum valor. Isto faz parte da questão mais ampla de quanto do VPS está realmente a confiar e de quem mais pode aceder ao disco subjacente.
FAQ
Uma soma de verificação correspondente significa que o download é seguro?
Não. Significa que os bytes que tem correspondem ao resumo criptográfico com o qual os comparou. Se o atacante controlar a página que publicou o resumo, pode publicar o resumo do seu próprio ficheiro, e a verificação apresenta OK. Uma correspondência confirma apenas a consistência. Para confirmar a segurança, é necessária uma assinatura verificada com uma chave obtida de outra fonte. Só depois disso o resumo criptográfico herda essa confiança.
Porque é que sha256sum -c apresenta FAILED open or read?
Porque nunca leu o ficheiro. Uma linha imediatamente acima indica No such file or directory com o nome que procurou. Os nomes num ficheiro SHA256SUMS são relativos ao diretório onde executa o comando. Por isso, mude para o diretório que contém o download e execute-o novamente. Se a lista também mencionar ficheiros que não descarregou, adicione --ignore-missing. Um FAILED simples, sem open or read, indica a situação oposta: o ficheiro foi lido e o seu resumo criptográfico não correspondeu.
O MD5 é suficiente para verificar um download?
Para detetar danos acidentais, sim. Uma transferência truncada ou um bloco defeituoso do disco não produzirá, por acaso, um resumo MD5 correspondente. Contra um atacante, não. É possível construir dois ficheiros diferentes com o mesmo resumo MD5 desde 2004, e o SHA-1 sofreu uma colisão de prefixo escolhido em 2020. Utilize a linha SHA-256 quando um projeto publicar ambas. Considere um projeto que use apenas MD5 como sinal de um processo de lançamento antigo.
Qual é a diferença entre sha256sum -c e gpg --verify?
sha256sum -c comprova que um ficheiro corresponde a um resumo criptográfico. gpg --verify comprova que um ficheiro de resumos criptográficos foi assinado pelo titular de uma determinada chave privada. Respondem a perguntas diferentes, por isso execute ambos quando um projeto disponibilizar ambos. A assinatura torna a lista de resumos criptográficos confiável. A lista de resumos criptográficos torna então o ficheiro descarregado confiável.
Como verifico um ficheiro contra um resumo criptográfico apresentado numa página web?
Não compare os caracteres visualmente. Guarde o resumo criptográfico e o nome do ficheiro numa única linha, separados por dois espaços. Em seguida, execute sha256sum -c contra esse ficheiro e leia o OK ou FAILED que apresentar. Criar a linha com printf '%s %s\n' evita os erros de formatação que fazem sha256sum rejeitar o ficheiro com no properly formatted checksum lines found.