Descarga con cURL y verifica sumas de comprobación SHA-256
Usa cURL para descargar un archivo y sha256sum para comparar sus bytes con una suma
de comprobación de confianza. El script Bash que se muestra a continuación mantiene la descarga en un
directorio temporal y le asigna su nombre de archivo definitivo solo después de que la verificación
se completa correctamente. Puedes ejecutar el mismo script localmente y en GitHub Actions.
Elige una suma de comprobación de confianza
SHA-256 produce un resumen de 256 bits, que suele escribirse como 64 caracteres hexadecimales. La coincidencia del resumen verifica los bytes descargados frente al valor esperado. No establece quién proporcionó ese valor: alguien que pueda reemplazar tanto una descarga como su suma de comprobación puede hacer que coincidan.
Obtén la suma de comprobación esperada de los metadatos de la versión del distribuidor a través de HTTPS y consérvala junto con la URL de la versión que quieras descargar. Si necesitas autenticar la versión de forma independiente de su sitio de alojamiento, sigue el procedimiento de verificación de firmas del distribuidor con una clave de firma cuya identidad hayas establecido de forma independiente. El proyecto cURL proporciona firmas separadas para los archivos de sus versiones; el ejemplo de suma de comprobación de esta página no verifica esas firmas.
Automatiza la verificación con Bash
Usa Linux con Bash, una compilación de cURL compatible con HTTPS y GNU coreutils:
sha256sum, mktemp, ln
y rm. El destino es el directorio actual, que debe permitir la escritura
y estar en un sistema de archivos compatible con enlaces duros. Se usa GNU
ln -T; no es un script portable de /bin/sh ni para macOS.
Los ejemplos se probaron con Bash 5.2.21, cURL 8.5.0 y coreutils 9.4 en Ubuntu 24.04, y con
Bash 5.3.15, cURL 8.22.0 y coreutils 9.11 en Linux.
Guarda este script como verify-download.sh en un directorio que controles. Ejecútalo con
Bash como se muestra a continuación; no lo cargues en tu shell mediante source. Los tres argumentos
son la URL HTTPS, el resumen SHA-256 esperado y un nombre de archivo local. Los nombres de salida
pueden contener espacios, guiones iniciales o caracteres % literales,
pero no deben contener barras ni saltos de línea. Si ya existe un archivo, directorio o enlace
simbólico con ese nombre, se produce un error y se deja intacto.
#!/usr/bin/env bash
set -euo pipefail
export LC_ALL=C
if [[ $# -ne 3 ]]; then
printf 'Usage: bash verify-download.sh HTTPS_URL SHA256 OUTPUT_NAME\n' >&2
exit 2
fi
url=$1
expected=$2
output=$3
if [[ $url != https://* || ! $expected =~ ^[[:xdigit:]]{64}$ ]]; then
printf 'Provide an HTTPS URL and a 64-digit hexadecimal SHA-256 checksum.\n' >&2
exit 2
fi
case "$output" in
''|.|..|*/*|*$'\n'*|*$'\r'*)
printf 'Provide a filename without slashes or line breaks.\n' >&2
exit 2
;;
esac
if [[ -e "./$output" || -L "./$output" ]]; then
printf 'Destination already exists: %s\n' "$output" >&2
exit 1
fi
umask 077
temp_dir=$(mktemp -d ./.verify-download.XXXXXX)
trap 'rm -rf -- "$temp_dir"' EXIT
trap 'exit 130' INT
trap 'exit 143' TERM
curl -q -fsSL --globoff --proto '=https' --proto-redir '=https' \
--connect-timeout 10 --max-time 120 --retry 3 \
--output "$temp_dir/payload" --url "$url"
if ! printf '%s %s\n' "$expected" "$temp_dir/payload" | sha256sum --check --status -; then
printf 'SHA-256 mismatch or unreadable download.\n' >&2
exit 1
fi
ln -T -- "$temp_dir/payload" "./$output"
printf 'Verified: %s\n' "$output"
Las opciones de cURL hacen que los errores HTTP, como un 404, provoquen
un fallo (-f), ocultan el indicador de progreso pero conservan los mensajes
de error (-sS) y siguen las redirecciones (-L).
Tanto la solicitud original como las redirecciones se restringen a HTTPS.
--globoff trata la URL de forma literal; -q, colocado
al principio, impide que un .curlrc local modifique la solicitud. Los fallos
transitorios se reintentan hasta tres veces, con un límite de 120 segundos por intento de transferencia.
El script construye un único registro de suma de comprobación: el resumen, dos espacios y la ruta
privada del archivo descargado.
GNU sha256sum --check
lee ese registro desde la entrada estándar. --status hace que el estado de salida
determine si la verificación se completó correctamente. Ningún archivo remoto de sumas de comprobación
puede elegir qué nombres de archivo locales se verifican.
Cuando hay coincidencia, GNU ln
añade el nombre definitivo al archivo ya verificado. -T trata el destino
como un nombre exacto, incluso cuando existe un directorio en esa ubicación, y la ausencia de
-f impide reemplazarlo. Mantener el directorio temporal junto al destino
sitúa ambos nombres en el mismo sistema de archivos. El manejador de salida elimina el nombre y el
directorio temporales; el archivo verificado permanece con su nombre definitivo.
Los fallos de descarga o de suma de comprobación devuelven un estado distinto de cero y eliminan los
datos temporales sin crear el archivo definitivo. Cada nueva ejecución inicia una descarga desde
cero; no se reanudan descargas parciales. Los manejadores también atienden las interrupciones normales,
pero un corte de energía o SIGKILL pueden dejar un directorio
.verify-download.* que habrá que eliminar manualmente. Esto permite descargar en un
directorio que te pertenece, pero no protege contra otro proceso que pueda modificar tus archivos.
Verifica una versión de cURL
La versión cURL 8.22.0 incluye
curl-8.22.0.tar.gz. Sus
metadatos de la versión indican que el valor de
digest de ese archivo concreto es
sha256:d54dd598bf05927a726deb38df31c6a255ba83ff1de57c5d1464dac3ed8f44a1.
Usa los 64 caracteres que siguen a sha256: como valor esperado. Los archivos
.tar.xz y .zip tienen bytes y sumas de comprobación
diferentes.
Estos son metadatos JSON, no un archivo de entrada para sha256sum --check. No intentes
adivinar una URL de suma de comprobación añadiendo .sha256 a una URL de descarga:
curl-8.5.0.tar.gz.sha256 no tiene ningún archivo en esa dirección. Aquí fijamos el resumen
publicado para el archivo de la versión y descargamos el archivo contenedor desde
curl.se:
bash verify-download.sh \
'https://curl.se/download/curl-8.22.0.tar.gz' \
'd54dd598bf05927a726deb38df31c6a255ba83ff1de57c5d1464dac3ed8f44a1' \
'curl-8.22.0.tar.gz'
Si se completa correctamente, el comando termina con estado cero e imprime:
Verified: curl-8.22.0.tar.gz
El archivo contenedor está ahora en tu directorio actual. Esto descarga código fuente; no instala ni actualiza cURL. Para repetir el ejemplo, usa otro nombre de salida o elimina deliberadamente la descarga anterior primero. Para verificar otra versión, selecciona su archivo exacto y actualiza tanto la URL como el resumen.
Integración con GitHub Actions
Mantén verify-download.sh en la raíz de tu repositorio y guarda este flujo de trabajo como
.github/workflows/verify-download.yml. Usa la misma URL y el mismo resumen fijados. El último paso muestra
el contenido del archivo contenedor verificado con tar y
gzip de Ubuntu; reemplaza ese paso por tu paso de compilación una vez que
la comprobación funcione.
name: Verify download
on: [push, pull_request]
permissions:
contents: read
jobs:
verify:
runs-on: ubuntu-24.04
timeout-minutes: 10
steps:
- uses: actions/checkout@v6
- name: Download and verify
shell: bash
run: |
bash verify-download.sh \
'https://curl.se/download/curl-8.22.0.tar.gz' \
'd54dd598bf05927a726deb38df31c6a255ba83ff1de57c5d1464dac3ed8f44a1' \
'curl-8.22.0.tar.gz'
- name: Read verified archive
shell: bash
run: tar -tzf curl-8.22.0.tar.gz > /dev/null
GitHub Actions detiene los pasos posteriores tras un fallo de forma predeterminada.
Conserva ese comportamiento: añadir continue-on-error o un
|| true que fuerce un resultado satisfactorio permitiría que un paso posterior
continuara después de un fallo de verificación. Revisa los cambios en las sumas de comprobación junto
con las actualizaciones de dependencias; calcular un resumen «esperado» a partir del archivo recién
descargado solo serviría para compararlo consigo mismo.
Solución de problemas
- Error HTTP, incluido
curl: (22): comprueba la URL exacta del archivo. Una página de error no debe convertirse en el archivo contenedor de tu versión. También se rechaza una redirección a HTTP, aunque el destino sea accesible. - Transferencia parcial, como
curl: (18): el servidor cerró la respuesta antes de que se recibiera la longitud anunciada. Reintenta después de comprobar la conexión. Si el servidor devuelve un archivo más corto como respuesta satisfactoria, la comparación de la suma de comprobación sigue rechazando los bytes modificados. - SHA-256 no coincide: compara la versión y la extensión del archivo contenedor con los metadatos del distribuidor. No reemplaces la suma de comprobación esperada por el valor de la descarga sospechosa.
- El destino ya existe: se conserva el archivo anterior. Elige otro nombre local o inspecciona y elimina tú mismo la descarga anterior.
- Error de enlace duro o de escritura: usa un sistema de archivos local que permita la escritura y admita enlaces duros. Si el paso de publicación falla, devuelve un estado distinto de cero aunque la suma de comprobación haya coincidido.
