Over the years, I've written hundreds, if not thousands, of shell scripts. With the ease at which you can redirect input and output within a shell script, many sysadmins store data in temporary files for processing purposes. In some situations scripts become essential to the day-to-day operations of a system and as such, may end up running on a regular basis via crontab – never to be looked at again.
Unfortunately, some sysadmins who write scripts might store sensitive data in temporary files, don't restrict access to temporary files, and might forget to remove them from the system when they are no longer needed. In many cases, they use them when it isn't even necessary. The beauty of Linux and UNIX is that there are hundreds of ways to accomplish the same task. I will keep my Bash examples simple so you can focus on grasping the general concepts.
Restrict access to temporary files
This is the most commonly forgotten step. If you are like most sysadmins who write temporary files to /tmp or /var/tmp, set your umask before file creation.
# cut -f1 -d: /etc/passwd > /tmp/test # ls -l /tmp/test -rw-r--r-- 1 root root 207 Dec 6 11:56 /tmp/test # rm -f /tmp/test
Now, let's set the umask, create the file again, and check its access controls:
# umask 077 # cut -f1 -d: /etc/passwd > /tmp/test # ls -l /tmp/test -rw------- 1 root root 207 Dec 6 11:58 /tmp/test # rm -f /tmp/test
As you can see, the more restrictive umask only grants the file owner read and write permission. Additionally, instead of writing temporary files to /tmp or /var/tmp, write the files to a dedicated, private area such as one under the user account's home directory. Limit access to this directory with permissions such as 0700.
Use a random string as the filename
To reduce the likelihood that someone knows the exact name of the temporary file your script creates, avoid using file name prefixes and use random characters as the filename. For example:
# umask 077 # tempfile=$(head -c 12 /dev/urandom |mimencode |tr -d "/") # echo $tempfile wwiboOPRHbozVuce # cut -f1 -d: /etc/passwd > /tmp/$tempfile # ls -l /tmp/$tempfile -rw------- 1 root root 207 Dec 6 12:10 /tmp/wwiboOPRHbozVuce # rm -f /tmp/$tempfile
Don't use temporary files at all
Of course, the safest method is to do in-line processing using pipes, a subshell environment, or a variable. For example, if you wanted an alphabetical listing of user accounts simply use a pipe:
# cut -f1 -d: /etc/passwd | sort -u
or even:
# sort -u -t: -k1 /etc/passwd |cut -f1 -d:
If you wanted to perform an action on each account on the system, invoke a subshell on a for...loop such as:
for user in $(cut -f1 -d: /etc/passwd)
do
printf "some action on %s\n" $user
done
Summary
In summary, take a look at your /var/tmp and /tmp directories. Do they have a bunch of strange files which are open to the world? Take inventory of all of the scripts running on your system especially those which are executed regularly via crontab. Make sure you clearly understand what they are doing and if they are creating any temporary files. If they do, try some of the aforementioned tips to help secure them.
POSIX compliant & relatively secure:
ReplyDelete# A random HEX number
suffix=`od -An -N32 -x /dev/urandom | tr -d "\n "`
if test $TMPDIR
then
root="$TMPDIR/$prog"
else
root="/tmp/$prog"
fi
temp="$root.$suffix"
fifo="$temp/fifo.$$"
rm_tmps() {
rm -rf "$root".* 2> /dev/null
}
no_dir() {
echo "Error: cannot create temp directory." 1>&2
exit 1
}
no_file() {
echo "Error: cannot create temp file/fifo." 1>&2
exit 1
}
on_trap() {
rm_tmps
exit 1
}
trap on_trap 1 2 3 4 15
rm_tmps
(umask 077 && mkdir "$temp") || no_dir
mkfifo "$fifo" || no_file
Oh... forgot...
ReplyDeleteprog="$0"
use mktemp(1)
ReplyDeleteUse /dev/shm for temporary files. Saves directly to RAM and is gone on reboot.
ReplyDeleteThanks for the article and comments!
ReplyDeleteThanks for the comments and feedback. Especially, the /dev/shm advice.
ReplyDeleteI believe there is a problem with the random string method. mimencode can include '/' in its output which would give an error when the directory isn't found.
ReplyDeleteThank you for that catch. Yes, mimencode could possibly include a slash. :-( I do like the other reader recommendations of using the octal dump command: od -An -N32 -x /dev/urandom |tr -d "\n "
ReplyDeleteOr... just throw the: tr -d "/" at the end of the pipe... I updated my example. Thanks again for the feedback.
ReplyDelete/dev/shm is OK - as long as you reboot oftem, which kind of goes against one reason for using a 'nix. Best bet is just to watch your housekeeping, and clean up after yourself.
ReplyDelete