Shell

如何重寫此函式以避免參數注入

  • April 3, 2017

我的.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 ...

至於$2and $3,傳遞它們與傳遞它們ssh基本相同evalor sh -c。它們內部的任何替換都將在遠端擴展。

說我們會跑ssh somehost "echo $var"。現在如果varcontains $(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 語言的所有可能的怪癖。

引用自:https://unix.stackexchange.com/questions/355453