¿Cómo puedo crear y acceder de manera segura a archivos temporales desde scripts de shell?

14

He leído que redirigir la salida a un archivo de nombre fijo /tmppuede ser un riesgo de seguridad, porque si un atacante (o descontento) se da cuenta de que /tmp/tmpfileformyscript.tmpse crea un archivo cuando ejecuto mi script (incluso si no tiene acceso de lectura a mi script), por ejemplo, puede hacer un enlace simbólico ln -s ~wildcard/.bashrc /tmp/tmpfileformyscript.tmpque hará que destruya mi .bashrcarchivo cuando ejecuto mi script.

Entonces, en cambio, puedo usar algo como filename="tmpfile.tmp.$RANDOM" ; echo outputtext > "$filename".

Sin embargo, a veces me gustaría usar un archivo tmp para el almacenamiento en caché, en cuyo caso me gustaría saber si "tmpfile.tmp. *" Coincide con algo /tmpy, de ser así, usar ese archivo en lugar de crear uno nuevo. Desafortunadamente, testel equivalente [ -f filename ]no admite el bloqueo de archivos hasta donde puedo decir.

Por lo tanto, mi pregunta es doble:

  1. ¿Cómo puedo crear un archivo temporal de forma segura? ¿Es "predictablename.$RANDOM"una práctica aceptable o hay una manera mejor (más segura, más fácil)?
  2. ¿Cómo puedo acceder fácilmente al archivo y / o establecer su existencia más adelante al verificarlo predictablename?
Comodín
fuente

Respuestas:

13

Use la mktemputilidad para crear un archivo temporal con un nombre impredecible. No está estandarizado por POSIX, pero está disponible en * BSD y Linux.

> /tmp/predictable.$RANDOMno es una buena opción porque es mayormente predecible¹, lo que abre su secuencia de comandos a un ataque en el que el atacante puede engañar a su secuencia de comandos para que sobrescriba un archivo al que tiene acceso de escritura, o para darles acceso al archivo temporal. Esta es una vulnerabilidad de archivo temporal insegura . mktempno tiene esta vulnerabilidad porque crea el archivo de forma segura (no sobrescribirá un archivo existente, incluso si están involucrados enlaces simbólicos) y usa un nombre suficientemente impredecible para evitar una denegación de servicio.

Si crear un archivo temporal y trabajar con él no es lo suficientemente bueno, cree un directorio temporal mktemp -dy trabaje allí.

mktemptambién tiene cuidado de usar $TMPDIRsi la variable está configurada, volviendo a /tmpsi no está configurada.

Cada vez más distribuciones configuradas TMPDIRpara ser un directorio privado, por ejemplo, /run/1234/tmpdónde 1234está su UID. Esto elimina el riesgo de vulnerabilidades de archivos temporales, a costa de no poder compartir archivos temporales entre usuarios (lo que ocasionalmente es útil, pero no muy a menudo; /tmptodavía está disponible, pero no lo es TMPDIR).

Si necesita un nombre de archivo reproducible, cree un archivo con un nombre bien definido (sin componente aleatorio) en el directorio de inicio del usuario. La convención moderna es la especificación del directorio de usuarios XDG . Si el archivo puede eliminarse sin causar pérdida de datos, use la XDG_CACHE_HOMEvariable de entorno, por defecto ~/.cache. Probablemente debería crear un subdirectorio con el nombre de su aplicación y trabajar allí.

CACHE_DIR="${XDG_CACHE_HOME:-"$HOME/.cache"}"/Wildcard-scripts
[ -d "$CACHE_DIR" ] || mkdir -p -- "$CACHE_DIR"
CACHE_FILE="$CACHE_DIR/tmpfileformyscript"

¹ No solo $RANDOMsolo toma 32767 valores posibles, sino que es fácil de predecir sin siquiera probar muchos valores. El generador de números aleatorios de Bash es un LCG sembrado por el PID y el momento del primer uso. Zsh es la plataforma randsembrada por el tiempo de inicio. ATT Ksh's es la plataforma randsembrada por PID. Mksh's es un LCG con una semilla más compleja, pero aún no de calidad de seguridad. Todos ellos pueden predecirse mediante otro proceso con una probabilidad bastante grande de éxito.

Gilles 'SO- deja de ser malvado'
fuente
En realidad, tu discusión sobre $TMPDIRy ~/.cachees exactamente lo que necesitaba. Después de pensarlo un poco más, me di cuenta de que la única razón por la que lo quería /tmpera particionar, por lo que el caché no podía llenar la /homepartición. Pero para este caso de uso que realmente no es un problema completo, entonces un subdirectorio se ~/.cacheadapta perfectamente a mis necesidades y evita el problema de seguridad.
Comodín el
mktempno está disponible en AIX o el shell Git en Windows. Parece que file.$RANDOM$RANDOMes la solución portátil. El $RANDOM$RANDOMdebe aumentar el espacio de 2 ^ 32, en el supuesto golpe de resultados aleatorios son independientes y no débil.
Los resultados aleatorios de @jww Bash son débiles: es un LCG, que es tan predecible como puede ser, pero es lo suficientemente bueno para muchas aplicaciones que no requieren imprevisibilidad.
Gilles 'SO- deja de ser malvado'
9

mktemp fue diseñado para esto. Desde la página del manual:

TMPFILE=`mktemp /tmp/example.XXXXXXXXXX` || exit 1
echo "program output" >> $TMPFILE

mktemp creará el archivo o saldrá con un estado de salida distinto de cero. El lógico o (||) asegura que el script saldrá si mktemp no puede crear el archivo. Después de este comando, puede estar seguro de que el archivo está disponible. No hay necesidad de revisarlo nuevamente. Lo único que puede necesitar agregar es la limpieza del archivo al final de su secuencia de comandos.

Y posiblemente también cuando el script termina con una señal. Si eso es necesario o no, es algo que debe decidir.

Ambos se pueden hacer usando el trapcomando.

Bram
fuente
Ah! Eso es muy útil; entonces no necesito llamar $RANDOM. Pero luego, la parte 2 de mi pregunta: ¿cómo puedo acceder a ese archivo más adelante o verificar si ya existe en una ejecución posterior del script? (Para implementar un caché muy simple.)
Comodín el