Security Considerations During File Manipulation In Bash Scripts
Publish date: Jun 19, 2019
Please read the following information carefully to avoid making mistakes when creating/moving/deleting files in bash scripts. Please note that this advice is applicable not only for sensitive files such as private keys, but also for non-sensitive files. Moreover, care should be taken not only for directories writable by others (e.g. /tmp) but also for directories that are only readable by others.
Set permissions before you create sensitive files, not after (use umask, not chmod)
For sensitive files that should not be world readable, it is not enough to create the file and then change the permissions to 600.
It is also a bad idea to change permissions before writing the sensitive data. When the permissions on an existing file are changed, those new permissions are only checked when opening the file. If a process has the file open already, it can continue to read that file (or write to that file if it was earlier opened in write mode).
The correct way to fix this is to change umask before creating any file. It is strongly encouraged to set umask at the beginning of each script.
# Store old umask value and set it to secure value
UMASK=$(umask)
umask 0077
# Creating new file (after umask)
touch /dir1/dir2/dir3/dir/newsecretfile
# Correct way to overwrite existing file: Set umask; Remove file if it exists; Create new file.
OFILE=/dir1/dir2/dir3/dir/existingfile
test -n "${OFILE}" && test -f "${OFILE}" && rm -f "${OFILE}"
cat /dirx/diry/secret.key > "${OFILE}"
# If you need to write to this file afterwards and in future, you can just use output redirect without needing these steps.
cat /dirx/diry/newsecret.key > "${OFILE}"
# Restore umask value to original value at the end
umask ${UMASK}
Exceptions: If you restart the system after changing permissions and before writing sensitive data, then it’s fine. If you change permissions and after that, ensure that no file descriptor to that file is open (“fuser” can give you that information), then it would be fine to write sensitive data to it as well. Basically, if no one has the file open after the permissions have been changed, then it is fine to write sensitive data to that file.
Always check permissions for the whole path
Check the permissions for the whole path leading to your file, not just the file and the parent directory. If one of the parent directories on the path to your file’s directory can be modified by someone else, they can hijack your whole path.
You can check permissions for whole path by using “namei”.
namei -m /dir1/dir2/dir3/dir/file
Always check permissions for the group as well. When checking permissions, look for the group permissions as well.
Creating temporary files in /tmp or other world-writable locations
Developers tend to create temporary files in world writable locations including but not limited to /tmp.
Using a fixed or easily predictable filename (/tmp/myservice.log or /tmp/myservice-[pid].log) is a bad idea. Same goes for folder names.
Instead use “mktemp” to generate filename in a secure fashion.
TMP_FILE=$(mktemp /tmp/myservice.log.XXXXXXXXXXXX)
# Use ${TMP_FILE} afterwards.
touch ${TMP_FILE}
If you need to create multiple files, use “mktemp -d” to create a directory. Then, you can use fixed names for files as long as they are created inside this directory.
TMP_DIR=$(mktemp /tmp/myservice.XXXXXXXXXXXX)
# Use ${TMP_DIR} as prefix to temporary files afterwards.
touch ${TMP_DIR}/myservice.log
touch ${TMP_DIR}/certificate.crt
Creating files (temporary or otherwise) in directories that are not accessible by others (directories with permission 700)
Check the permissions of all parent directories to make sure they are not writable by others. Check again that the directory which will contain the file has permission 700 and owned by expected user and group. Go ahead. Do what you want. You have deserved it.
Creating files (temporary or otherwise) in directories that are executable (but not writable) by others (directories with permission 755 or similar)
No, read permission on parent directories is not required by others to access your file. That just allows them to read the names of files in that directory (“ls” output). The executable permission controls access to files inside the directory.
If the files are not sensitive and you don’t care who reads that information, you can make it 755.
If the file contents are meant to be overwritten by others, you can make it 777. You don’t need and should not set 777 on any of the parent directories. Others don’t need that to write to your world-writable file.
If you are writing sensitive data to file, set “umask 0077”, then create the file. Don’t write to an existing file (unless it was created with 600 permission). No, doing “chmod 600” to existing file before writing sensitive data will not help; anyone with open file descriptor will still be able to read it as long as they keep the file descriptor open). For more details and example, see the umask example.
And of course, encrypt the sensitive data (or don’t write it if not really needed, e.g. in logs). Don’t store it in plaintext.