如何重寫此函式以避免參數注入
我的
.bashrc
文件中有一個函式,允許我通過 ssh 在遠端伺服器上執行帶有參數的腳本。目前,該功能包含:
function runMyScript { if [ $1 = "s3" ] then ssh -i "~/path/to/.pem" server.amazonaws.com "/home/ubuntu/scripts/script.sh ${1} ${2} ${3}" elif [ $1 = "ec2" ] then ssh -i "~/path/to/.pem" server.amazonaws.com "/home/ubuntu/scripts/script.sh ${1} ${2}" else echo "** Run with s3 or ec2 options" fi }
因此,我可以使用
runMyScript arg_1 arg_2 arg_3
或呼叫該函式runMyScript arg_1 arg_2
。如何重寫此函式以使其更安全並避免可能的參數注入?
如何避免可能的參數注入?
找出你想要傳遞的輸入類型,並確保參數只包含那些。
至少,確保它們不包含遠端 shell 特有的字元。
$1
問題不大,因為您將其與已知值進行比較。雖然您需要雙引號,否則它可能會在比較中擴展為多個單詞,這可能允許通過它傳遞有趣的值(類似於1 -o x
通過比較的東西)。改為使用
if [ "$1" = "s3" ] ; then ...
。至於
$2
and$3
,傳遞它們與傳遞它們ssh
基本相同eval
orsh -c
。它們內部的任何替換都將在遠端擴展。說我們會跑
ssh somehost "echo $var"
。現在如果var
contains$(ls -ld /tmp)
,遠端命令行將為echo $(ls -ld /tmp)
,並ls
在遠端執行。雙引號變數對命令擴展沒有幫助,但單引號會。將命令寫為ssh somehost "echo '$var'"
,不會發生命令擴展。變數中的單引號仍然是一個問題,因為它們會終止單引號,所以至少,我們需要檢查一下:
case "$var" in *"'"*) echo var has a single-quote; exit 1 ;; esac
儘管我們不妨檢查任何我們不想通過的特殊字元。美元符號開始大多數擴展,反引號開始命令擴展,以及我也不信任的引號:
case "$var" in *[\'\"\$\`]*) echo var has something funny; exit 1 ;; esac
但我不確定是否僅此而已,所以最好將我們想要通過的字元列入白名單。如果字母、數字、破折號和下劃線就足夠了:
case "$var" in *[!-_a-zA-Z0-9]*) echo var has something funny; exit 1 ;; esac
所以,這可能是一個開始:
function runMyScript { case "$2" in *[!-_a-zA-Z0-9]*) exit 1 ;; esac case "$3" in *[!-_a-zA-Z0-9]*) exit 1 ;; esac if [ "$1" = "s3" ] ; then ssh somehost "script.sh '$1' '$2' '$3'" elif [ "$1" = "ec2" ] ; then ssh somehost "script.sh '$1' '$2'" else echo "** Run with s3 or ec2 options" fi }
請注意,您使用
function runMyScript
而不是runMyScript()
,您沒有執行普通的 POSIX shell。如果碰巧是 Bash,你可以用支持正則表達式匹配的[[...]]
測試重寫模式匹配。新版本的 Bash 也有
${var@Q}
擴展,它應該以var
可以重用作為輸入的格式生成引用的內容。它也可能有用,但我手頭沒有足夠新的 bash 來測試它。另外,不要盲目相信我會記住 shell 語言的所有可能的怪癖。