是否可以安全地使用find -exec sh -c
?
我正在嘗試將
find
toecho 0
用於某些文件,但顯然這只適用於sh -c
:find /proc/sys/net/ipv6 -name accept_ra -exec sh -c 'echo 0 > {}' \;
但是使用
sh -c
withfind -exec
讓我感到非常不安,因為我懷疑引用有問題。我擺弄了一下,顯然我的懷疑是有道理的:
- 我的測試設置:
martin@dogmeat ~ % cd findtest martin@dogmeat ~/findtest % echo one > file\ with\ spaces martin@dogmeat ~/findtest % echo two > file\ with\ \'single\ quotes\' martin@dogmeat ~/findtest % echo three > file\ with\ \"double\ quotes\" martin@dogmeat ~/findtest % ll insgesamt 12K -rw-rw-r-- 1 martin martin 6 Sep 17 12:01 file with "double quotes" -rw-rw-r-- 1 martin martin 4 Sep 17 12:01 file with 'single quotes' -rw-rw-r-- 1 martin martin 4 Sep 17 12:01 file with spaces
- 使用
find -exec
withoutsh -c
似乎沒有問題 - 這裡不需要引用:martin@dogmeat ~ % find findtest -type f -exec cat {} \; one two three
- 但是當我使用時
sh -c
{}
似乎需要某種引用:martin@dogmeat ~ % LANG=C find findtest -type f -exec sh -c 'cat {}' \; cat: findtest/file: No such file or directory cat: with: No such file or directory cat: spaces: No such file or directory cat: findtest/file: No such file or directory cat: with: No such file or directory cat: single quotes: No such file or directory cat: findtest/file: No such file or directory cat: with: No such file or directory cat: double quotes: No such file or directory
- 只要沒有文件名包含雙引號,雙引號就可以工作:
martin@dogmeat ~ % LANG=C find findtest -type f -exec sh -c 'cat "{}"' \; one two cat: findtest/file with double: No such file or directory cat: quotes: No such file or directory
- 只要文件名不包含單引號,單引號就可以工作:
martin@dogmeat ~ % LANG=C find findtest -type f -exec sh -c "cat '{}'" \; one cat: findtest/file with single: No such file or directory cat: quotes: No such file or directory three
我還沒有找到適用於所有情況的解決方案。有沒有我忽略的東西,或者
sh -c
在find -exec
本質上是不安全的?
永遠不要嵌入
{}
到 shell 程式碼中!這會產生命令注入漏洞。請注意,對於cat "{}"
,它不僅與"
字元有關,\
,```也是$
一個問題(例如,考慮一個名為 的文件./$(reboot)/accept_ra
)¹。(順便說一句,某些
find
實現不會讓您這樣做,並且POSIX{}
未在參數中單獨指定行為時find -exec
)在這裡,您希望將文件名作為單獨的參數傳遞給
sh
(而不是在程式碼參數中),並通過sh
內聯腳本(程式碼參數)使用位置參數來引用它們:find . -name accept_ra -exec sh -c 'echo 0 > "$1"' sh {} \;
或者,為了避免
sh
每個文件執行一個:find . -name accept_ra -exec sh -c 'for file do echo 0 > "$file"; done' sh {} +
這同樣適用於
xargs -I{}
orzsh
。zargs -I{}
不要寫:<list.txt xargs -I{} sh -c 'cmd > {}'
這將是與上述相同的命令注入漏洞
find
,但是:<list.txt xargs sh -c 'for file do cmd > "$file"; done' sh
這還具有避免每個文件執行一個以及不包含任何文件
sh
時的錯誤的好處。list.txt
使用
zsh
’szargs
,您可能想要使用函式而不是呼叫sh -c
:do-it() cmd > $1 zargs ./*.txt -- do-it
請注意,在上面的所有範例中,上面第二個
sh
都進入了內聯腳本的$0
. 您應該在此處使用相關的內容(例如sh
orfind-sh
),而不是 , 或空字元串之類_
的內容,因為 in 的值-
用於shell 的錯誤消息:--``$0
$ find . -name accept_ra -exec sh -c 'echo 0 > "$1"' inline-sh {} \; inline-sh: ./accept_ra: Permission denied
GNU
parallel
的工作方式不同。有了它,您不想使用sh -c
asparallel
does 已經執行 shell 並嘗試{}
用正確語法中引用的參數替換 shell。<list.txt PARALLEL_SHELL=sh parallel 'cmd > {}'
¹ 並且根據
sh
實現,其他字元的編碼包含這些字元的編碼(在實踐中和現實生活中的字元編碼,僅限於字節 0x5c 和 0x60)