Ensure Variable Contains Valid Filename – Safe Shell Scripting

centosfilesrmSecurityshell-script

Given the script below, how can I ensure that the argument only contains a valid filename within /home/charlesingalls/ and not a path (../home/carolineingalls/) or wildcard, etc?

I only want the script to be able to delete a single file from the given hard-coded directory. This script will run as a privileged user.

#!/bin/bash

rm -f /home/charlesingalls/"$1"

Best Answer

If you only want to delete a file in /home/charlesingalls (and not a file in a subdirectory) then it's easy: just check that the argument doesn't contain a /.

case "$1" in
  */*) echo 1>&2 "Refusing to remove a file in another directory"; exit 2;;
  *) rm -f /home/charlesingalls/"$1";;
esac

This runs rm even if the argument is . or .. or empty, but in that case rm will harmlessly fail to delete a directory.

Wildcards are not relevant here since no wildcard expansion is performed.

This is safe even in the presence of symbolic links: if the file is a symbolic link, the symlink (which is in /home/charlesingalls) gets removed, and the target of that link is not affected.

Note that this assumes that /home/charlesingalls cannot be moved or changed. That should be ok if the directory is hard-coded in the script, but if it's determined from variables then the determination might no longer be valid by the time the rm command runs.

Based on the additional information that the argument is a virtual host name, you should do whitelisting rather than blacklisting: check that the name is a sensible virtual host name, rather than just banning slashes. I check that the name starts with a lowercase letter or digit and that it does not contain characters other than lowercase letters, digits, dots and dashes.

LC_CTYPE=C LC_COLLATE=C
case "$1" in
  *[!-.0-9a-z]*|[!0-9a-z]*) echo >&2 "Invalid host name"; exit 2;;
  *) rm -f /home/charlesingalls/"$1";;
esac
Related Question