should I avoid bash -c, sh -c, and other shells' equivalents in my shell scripts?

后端 未结 2 1073
余生分开走
余生分开走 2021-01-07 05:11

Consider the following code:

#!/bin/bash -x
VAR=\'1 2 3\'
bash -c \"echo \"\\$$VAR\"\"
eval \"echo \"\\$$VAR\"\"
bash -c \"echo \\\"\\$$VAR\\\"\"
eval \"echo         


        
2条回答
  •  迷失自我
    2021-01-07 05:57

    Yes, you should avoid using sh -c and equivalents in your shell scripts, just as you avoid eval.

    eval "$foo"
    

    ...is, when one boils it down, a security risk because it treats data as code, restarting the parsing process at the very beginning (thus, running expansions, redirections, etc). Moreover, because quoting contexts are considered in this process, content inside of the data being evaluated is able to escape quotes, terminate commands, and otherwise attempt to evade any efforts made at security.

    sh -c "$foo"
    

    does the same -- running expansions, redirections, and the like -- only in a completely new shell (not sharing non-exported variables or other state).

    Both of these mean that content such as $(rm -rf /) is prone to being expanded unless great care is taken, rather than ensuring that -- as is generally the case -- data will only ever be treated as data, which is a foundational element of writing secure code.


    Now, the happy thing here is that when you're using bash (or zsh, or ksh93) rather than sh, you can avoid using eval in almost all cases.

    For instance:

    value=$(eval "echo \$$varname")
    

    ...can be replaced with:

    value=${!varname}
    

    ...and in bash,

    eval "$varname="'$value'
    

    ...can be replaced with...

    printf -v varname %s "$value"
    

    ...and so forth (with ksh93 and zsh having direct equivalents to the latter); more advanced formulations involving associative maps and the like are best addressed with the new bash 4.3 (and ksh93) namevar support.


    Notably, bash -c doesn't replace eval effectively in most of the above examples, because it doesn't run in the same context: Changes made to shell state are thrown away when the child process exits; thus, not only does bash -c not buy safety, but it doesn't work as an eval replacement to start with.

提交回复
热议问题