Arrays 使用函数输出中的引用值初始化bash数组最安全的方法是什么?
我更喜欢将bash脚本编程为尽可能程序化的脚本。我在尝试这样做时遇到的一个困难是在函数之间传递数组数据,这是bash中不支持的任务 例如,在bash中用多个硬编码、带引号的值初始化一个数组非常简单,每个值可能包含多个单词:Arrays 使用函数输出中的引用值初始化bash数组最安全的方法是什么?,arrays,bash,interpolation,Arrays,Bash,Interpolation,我更喜欢将bash脚本编程为尽可能程序化的脚本。我在尝试这样做时遇到的一个困难是在函数之间传递数组数据,这是bash中不支持的任务 例如,在bash中用多个硬编码、带引号的值初始化一个数组非常简单,每个值可能包含多个单词: declare -a LINES=( "Hello there" "loyal user" ) echo "Line 0: '${LINES[0]}'" echo "Line 1: '${LINES[1]}'" # Line 0: 'Hello there' # Line 1
declare -a LINES=( "Hello there" "loyal user" )
echo "Line 0: '${LINES[0]}'"
echo "Line 1: '${LINES[1]}'"
# Line 0: 'Hello there'
# Line 1: 'Loyal user'
但是,用函数的输出替换这些硬编码值似乎效果不太好:
getLines() {
echo "\"Hello there\" \"loyal user\""
}
local LINE_STR=$( getLines )
declare -a LINES=( ${LINE_STR} )
echo "Line 0: '${LINES[0]}'"
echo "Line 1: '${LINES[1]}'"
# Line 0: '"Hello'
# Line 1: 'there"'
为了克服这个问题,我尝试了几乎所有允许bash语句的排列。“评估”似乎是一种行之有效的方法:
local LINE_STR=$( getLines )
eval declare -a LINES=( ${LINE_STR} )
echo "Line 0: '${LINES[0]}'"
echo "Line 1: '${LINES[1]}'"
# Line 0: 'Hello there'
# Line 1: 'loyal user'
但是,这种方法涉及到安全问题,如下所示:
emulateUnsafeInput() {
echo "\"\`whoami\` just got haxxored\" \"Hahaha!\""
}
local LINE_STR=$( emulateUnsafeInput )
eval declare -a LINES=( "${LINE_STR}" )
echo "Line 0: '${LINES[0]}'"
echo "Line 1: '${LINES[1]}'"
# Line 0: 'root just got haxxored'
# Line 1: 'Hahaha!'
“read-a”似乎是一个可能的解决方案,尽管这是一个有问题的解决方案,因为当数据通过管道传输到子shell中时,“read”将在子shell中运行,从而有效地将其变量堆栈与调用脚本的变量堆栈分离
< >我应该考虑什么样的解决方案来缓解“EVE”方法的安全性问题?我包含了以下脚本,演示了我尝试过的无数方法:
#!/bin/bash
getLines() {
echo "\"Hello there\" \"loyal user\""
}
emulateUnsafeInput() {
echo "\"\`whoami\` just got haxxored\" \"Hahaha!\""
}
execute() {
(
echo Test 01
declare -a LINES=( "Hello there" "loyal user" )
echo "Line 0: '${LINES[0]}'"
echo "Line 1: '${LINES[1]}'"
# Line 0: 'Hello there'
# Line 1: 'loyal user'
);(
echo Test 02
local LINE_STR=$( getLines )
declare -a LINES=( ${LINE_STR} )
echo "Line 0: '${LINES[0]}'"
echo "Line 1: '${LINES[1]}'"
# Line 0: '"Hello'
# Line 1: 'there"'
);(
echo Test 03
local LINE_STR=$( getLines )
declare -a LINES=( "${LINE_STR}" )
echo "Line 0: '${LINES[0]}'"
echo "Line 1: '${LINES[1]}'"
# Line 0: '"Hello there" "loyal user"'
# Line 1: ''
);(
echo Test 04
local LINE_STR=$( getLines )
eval declare -a LINES=( ${LINE_STR} )
echo "Line 0: '${LINES[0]}'"
echo "Line 1: '${LINES[1]}'"
# Line 0: 'Hello there'
# Line 1: 'loyal user'
);(
echo Test 05
local LINE_STR=$( getLines )
eval declare -a LINES=( "${LINE_STR}" )
echo "Line 0: '${LINES[0]}'"
echo "Line 1: '${LINES[1]}'"
# Line 0: 'Hello there'
# Line 1: 'loyal user'
);(
echo Test 06
local LINE_STR=$( getLines )
declare -a LINES=( $( echo ${LINE_STR} ) )
echo "Line 0: '${LINES[0]}'"
echo "Line 1: '${LINES[1]}'"
# Line 0: '"Hello'
# Line 1: 'there"'
);(
echo Test 07
local LINE_STR=$( getLines )
declare -a LINES=( $( echo "${LINE_STR}" ) )
echo "Line 0: '${LINES[0]}'"
echo "Line 1: '${LINES[1]}'"
# Line 0: '"Hello'
# Line 1: 'there"'
);(
echo Test 08
local LINE_STR=$( getLines )
declare -a LINES=( $( eval echo ${LINE_STR} ) )
echo "Line 0: '${LINES[0]}'"
echo "Line 1: '${LINES[1]}'"
# Line 0: 'Hello'
# Line 1: 'there'
);(
echo Test 09
local LINE_STR=$( getLines )
declare -a LINES=( $( eval echo "${LINE_STR}" ) )
echo "Line 0: '${LINES[0]}'"
echo "Line 1: '${LINES[1]}'"
# Line 0: 'Hello'
# Line 1: 'there'
);(
echo Test 10
local LINE_STR=$( emulateUnsafeInput )
eval declare -a LINES=( ${LINE_STR} )
echo "Line 0: '${LINES[0]}'"
echo "Line 1: '${LINES[1]}'"
# Line 0: 'root just got haxxored'
# Line 1: 'Hahaha!'
);(
echo Test 11
local LINE_STR=$( emulateUnsafeInput )
eval declare -a LINES=( "${LINE_STR}" )
echo "Line 0: '${LINES[0]}'"
echo "Line 1: '${LINES[1]}'"
# Line 0: 'root just got haxxored'
# Line 1: 'Hahaha!'
);(
echo Test 12
local LINE_STR=$( emulateUnsafeInput )
declare -a LINES=( $( eval echo ${LINE_STR} ) )
echo "Line 0: '${LINES[0]}'"
echo "Line 1: '${LINES[1]}'"
# Line 0: 'root'
# Line 1: 'just'
);(
echo Test 13
local LINE_STR=$( emulateUnsafeInput )
declare -a LINES=( $( eval echo "${LINE_STR}" ) )
echo "Line 0: '${LINES[0]}'"
echo "Line 1: '${LINES[1]}'"
# Line 0: 'root'
# Line 1: 'just'
)
}
execute
对于数据功能,使用echo-e并用换行符分隔数据:
getLines() { echo -e "\"Hello there\"\n\"loyal user\""; }
要读取数据,请使用进程替换和重定向:
i=0
while read -r
do
arr[i++]=$REPLY
done < <(getLines)
# Line 0: '"Hello there"'
# Line 1: '"loyal user"'
i=0
而read-r
做
arr[i++]=$REPLY
完成以下操作:
如果您担心来自函数的任意恶意数据,只需使用\0
(又称NUL
)分隔符来预期和解析字符串即可。它是唯一不能成为任何变量一部分的字符,因此不可能与实际数据发生冲突
haxxorz() {
printf '%s\0' whoami
printf '%s\0' '\`whoami\`'
printf '%s\0' "\`whoami\`"
printf '%s\0' "\"\`whoami\` is haxxor-proof"'!'"\""
printf '%s' 'Trying to poison the $REPLY variable with a missing separator'
}
index=0
while IFS= read -r -d '' || [ -n "$REPLY" ]
do
array[index++]="$REPLY"
done < <(haxxorz)
for element in "${array[@]}"
do
echo "$element"
done
echo "${REPLY:-REPLY is empty}"
我喜欢一个计划的结合
haxxorz() {
printf '%s\0' whoami
printf '%s\0' '\`whoami\`'
printf '%s\0' "\`whoami\`"
printf '%s\0' "\"\`whoami\` is haxxor-proof"'!'"\""
printf '%s' 'Trying to poison the $REPLY variable with a missing separator'
}
index=0
while IFS= read -r -d '' || [ -n "$REPLY" ]
do
array[index++]="$REPLY"
done < <(haxxorz)
for element in "${array[@]}"
do
echo "$element"
done
echo "${REPLY:-REPLY is empty}"
whoami
\`whoami\`
`whoami`
"`whoami` is haxxor-proof!"
Trying to poison the $REPLY variable with a missing separator
REPLY is empty