Seguridad en Scripts Bash
Los scripts mal escritos pueden:
- Exponer datos sensibles (tokens, contraseñas).
- Permitir inyección de comandos peligrosos.
- Ser explotados por archivos con nombres maliciosos.
- Romperse al ejecutarse en diferentes entornos.
En este módulo aprenderás las mejores prácticas de seguridad en Bash.
1. Configuración segura con set #
Al inicio de los scripts críticos, activa estas opciones:
1#!/usr/bin/env bash 2set -Eeuo pipefail
| Opción | Protege contra… |
|---|---|
-e | Continuar el script tras un fallo. |
-u | Usar variables no definidas. |
-o pipefail | Ignorar fallos en pipelines. |
-E | Ignorar traps de error en funciones/subshells. |
👉 Con esto, el script fallará rápido si algo sale mal.
2. Manejo seguro de variables de entrada #
Nunca asumas que los argumentos del usuario son seguros.
Ejemplo inseguro:
1ARCHIVO=$1 2cat $ARCHIVO
👉 Si el usuario pasa "; rm -rf /", podría ejecutarse un comando malicioso.
Solución: cita y valida las variables #
1ARCHIVO="$1" 2 3 # Verifica que el archivo exista 4if [[ ! -f "$ARCHIVO" ]]; then 5 echo "❗ Error: archivo no encontrado" 6 exit 1 7fi 8 9 # Usa comillas siempre 10cat "$ARCHIVO"
3. Validación de entrada #
Antes de usar variables externas:
- Comprueba existencia de archivos o carpetas.
- Valida tipos numéricos.
- Limita longitud y caracteres permitidos.
Ejemplo: validar que un argumento es un número entero positivo:
1if [[ ! "$1" =~ ^[0-9]+$ ]]; then 2 echo "❗ Error: se esperaba un número entero positivo" 3 exit 1 4fi
4. Riesgo del word splitting y del IFS #
Por defecto, Bash separa valores por espacios. Esto puede romper scripts con nombres de archivos que contengan espacios.
Ejemplo inseguro:
1for f in $(ls *.txt); do 2 echo "Archivo: $f" 3done
👉 Fallará con nombres como mis datos.txt.
Solución: usa arrays o find ... -print0 #
1IFS=$'\n' # separador de líneas 2for f in *.txt; do 3 echo "Archivo: $f" 4done
O mejor:
1find . -name "*.txt" -print0 | while IFS= read -r -d '' f; do 2 echo "Archivo: $f" 3done
👉 -print0 y -d '' protegen contra espacios y caracteres especiales.
5. No dependas del PATH #
Un atacante podría poner un comando falso con el mismo nombre en otra carpeta. Siempre usa rutas absolutas en scripts críticos.
Malo:
1cp archivo /destino
Mejor:
1/usr/bin/cp archivo /destino
6. Manejo de datos sensibles #
Nunca pongas contraseñas o tokens en el propio script. Usa variables de entorno o archivos de configuración con permisos restringidos.
1DB_PASS="${DB_PASS:?Error: la variable DB_PASS no está definida}"
👉 El script fallará si DB_PASS no está definida.
7. Evitar inyección en comandos externos #
Al construir comandos con datos externos, cítalos.
Ejemplo inseguro:
1usuario=$1 2id $usuario
Si el usuario pasa "; rm -rf /", se ejecutaría algo destructivo.
✅ Solución:
1usuario="$1" 2id -- "$usuario"
👉 El -- indica el fin de las opciones y evita interpretaciones maliciosas.
8. Uso seguro de archivos temporales #
No uses nombres fijos (riesgo de colisiones e inyección).
Malo:
1TMP=/tmp/temporal.txt
Mejor:
1TMP=$(mktemp)
👉 mktemp crea archivos únicos y seguros.
9. Limitar permisos y privilegios #
- Ejecuta los scripts con el usuario menos privilegiado posible.
- Cambia permisos de archivos sensibles:
1chmod 600 ~/.config/mi_app.conf
- Si un script necesita permisos de superusuario, usa
sudosolo donde sea necesario.
10. Limpiar datos temporales con trap #
1TMP=$(mktemp) 2trap 'rm -f "$TMP"' EXIT 3 4echo "Datos sensibles" > "$TMP"
👉 El archivo temporal se elimina aunque el script falle o se interrumpa.
11. Ejemplo integrador: procesamiento seguro de logs #
1#!/usr/bin/env bash 2set -Eeuo pipefail 3 4LOGDIR="$1" 5 6 # Validar argumento 7if [[ -z "$LOGDIR" || ! -d "$LOGDIR" ]]; then 8 echo "❗ Error: debes proporcionar un directorio válido" 9 exit 1 10fi 11 12TMP=$(mktemp) 13trap 'rm -f "$TMP"' EXIT 14 15 # Buscar logs y contar errores 16find "$LOGDIR" -type f -name "*.log" -print0 | \ 17while IFS= read -r -d '' archivo; do 18 grep -c "ERROR" "$archivo" >> "$TMP" 19done 20 21echo "Total de errores: $(awk '{s+=$1} END{print s}' "$TMP")"
👉 Buenas prácticas aplicadas:
set -Eeuo pipefail→ script robusto ante fallos.- Validación de entrada.
- Manejo seguro de archivos temporales.
- Citas correctas para evitar inyecciones.
12. Ejercicio práctico 1 #
Crea un script importa_datos.sh que:
- Acepte un archivo CSV como argumento.
- Verifique que el archivo existe y tiene extensión
.csv. - Use
mktemppara almacenar un log temporal. - Procese el archivo con
awkpara mostrar el total de líneas. - Elimine el archivo temporal al finalizar (usa
trap).
13. Ejercicio práctico 2 #
Crea un script backup_seguro.sh que:
- Acepte como argumento el directorio a respaldar.
- Valide que existe.
- Cree un backup comprimido con fecha.
- Use rutas absolutas para los comandos críticos.
- Genere logs con permisos restrictivos (
chmod 600).
14. Ejercicio práctico 3 #
Crea un script usuario_seguro.sh que:
- Acepte como argumento un nombre de usuario.
- Verifique que el nombre solo contiene letras y números.
- Cree un archivo temporal para registrar el resultado.
- Use
id -- "$usuario"para mostrar información del usuario. - Elimine el archivo temporal al salir.
15. Buenas prácticas de seguridad #
- ✅ Usa
set -Eeuo pipefailen scripts críticos. - ✅ Valida SIEMPRE la entrada del usuario.
- ✅ Usa comillas dobles
"$VAR"y--para evitar inyecciones. - ✅ No dependas del
PATH: usa rutas absolutas. - ✅ Protege datos sensibles en variables de entorno y archivos de configuración.
- ✅ Limpia archivos temporales con
trapymktemp.
Resumen del tema
Conceptos clave #
- Prevención de Inyección de Comandos: entrecomillado estricto
"$VAR", uso del delimitador--para cesar análisis de flags y validación de tipos mediante regex ([[ "$1" =~ ^[0-9]+$ ]]). - Mitigación de Word Splitting: evitar
$(ls)y utilizar en su lugarfind ... -print0 | while IFS= read -r -d '' f; do ... done. - Manejo Seguro de Archivos Temporales: creación no predecible con
mktempy vinculación contrap 'rm -f "$TMP"' EXIT. - Seguridad en Secretos: evitar credenciales en texto plano; validar presencia de variables de entorno críticas con
${SECRET:?Error: no definido}y asignar permisoschmod 600a ficheros de configuración. - Independencia del
PATH: uso de rutas absolutas para binarios de administración críticos.
Qué debes recordar #
Cita siempre todas las variables "$VAR", valida entradas de usuario con regex y genera temporales con mktemp y trap para blindar tus scripts.