Logan Hartman Logan Hartman - 2 months ago 6
Bash Question

Secure Input Validation in Bash/Shell Script

I'm writing a bash script that requires several pieces of user input, primarily directory paths and file names. The program will create the specified directories and files.

When writing the directory path, I request the absolute path - ~/DIR/..., or $PATH/DIR/... or ./DIR/... are not allowed. Directory paths should only be provided in the form of /DIR/DIR/..., file paths in the form /DIR/DIR/.../filename, and file names in the form of filename.
I also want to assure the user has not added any command-line options (for example, if I run sudo, I want to assure that the user has not appended -u anywhere in their statement) to their input.

However, I'm not entirely certain of the best way to sanitize their input, since directory paths and filenames may contain dashes, underscores, spaces, periods, and alphanumeric characters. Any other character should be detected.

User input is gathered through read. I'm using an Ubuntu system, so as long as it complies with Ubuntu shell then it'll work.
Assume that only the default system packages are installed.

Multiple options are acceptable to handle individual sections of validation (e.g. using

to treat following data as a parameter and not a command [suggested by Siguza], and then another option for handling directory paths).

Absolute paths are required for correct mapping of directory structure. Any other format of path would cause the program to incorrectly interpret the structure when matched or appended to other paths, due to the functions I'm performing on the strings of paths.

Thank you.

What worked: I used the accepted answer, using realpath in some situations and readlink, and using -- to interpret the following text as parameters. If you want to allow relative paths, then use the result of readlink or realpath as your path. If you want to disallow relative paths, then compare the original string to the result of readlink or realpath.


You could do something like this:


set -e    

while read path; do
    result=`realpath -m -- "$path"`
    if [ "$result" != "$path" ] && [ "$result/" != "$path" ] ; then
        echo "Rejected: $path"
        if [ "$last_char" == "/" ]; then
            echo "New directory: $path"
            mkdir -- "$path"
            echo "New file: $path"
            touch -- "$path"

exit 0

I use realpath to catch relative paths, then always use user input between double quotes to avoid commands injection (if any is possible). I guess there are better ways of doing but at the moment that's all I can think of.

Edit: as advised in the comments, I added -- to ensure the file/directory names are safely given to touch, mkdir and realpath.