安全bash配置文件



我想从配置文件中配置bash脚本。

我想要一个类型的安全且稳健的解决方案。

  • [robust]:不要试图用正则表达式太聪明(和bug(

因此,最"常见"的解决方案,即配置文件的来源,对我来说不是一个选项,因为下面的配置文件会做一些有趣的事情:

touch your_computer_is_hacked
foo=bar

配置文件的最佳做法是什么?所以我可以把所有的值都放在一个关联数组中?我不在乎实际的格式(bash脚本、yaml、ini、xml、javascript(,但它应该完全指定,所以如果我想在foo变量中添加一个空格/newline或õ字符,应该指定如何执行。

我认为最好的选择是编写source <(...),其中...是一个从标准输入中读取并写出所需映射的命令。这样,...可以是Perl脚本、Python脚本或其他类似的脚本,这比在纯Bash中执行更容易。

这个答案的底部是一个满足您要求的简单示例。它创建了一个名为source-assoc-array的函数,该函数使用从标准输入读取的信息(在典型情况下,将从文件重定向(填充由调用方指定的关联数组(调用方需要预先声明(。传递标准输入的格式如下:

  • 每行一个赋值。没有空行,没有注释行,没有跨多行的赋值,除了赋值之外没有其他命令
  • 每个作业的形式为key=value。不允许空白,当然value可以包含空白
  • 密钥是一个或多个ASCII字母、数字和下划线,而不是以数字开头。(这些是Bash变量名的规则。(
  • 该值为零个或多个非空字节。(Bash字不能包含空字节,所以这是一个不可避免的限制。(换行符表示为n;反斜杠表示为\;所有其他字节都表示为它们自己
  • 因此,例如,如果arr是关联数组的名称,则将行foo='barn\nbaz'转换为arr[foo]=$''barn\nbaz''
  • 如果遇到任何不符合上述规则的行,函数将中止并显示错误消息

通过支持各种功能,如空行、注释、前导和尾部空白(包括尾部回车,以支持Windows行结尾(、=周围的空白以及除n\之外的其他转义序列,您可以轻松地使格式更加用户友好。

你可能还想仔细考虑一下你的威胁模型。例如,如果用户在文件中放入奇怪的字符(回车、从右到左的字符、控制字符等(,这会让系统管理员很难准确理解映射是什么吗?(由于这个原因,下面的函数会发出错误消息,其中不包括有问题的行,只包括行号。(用户是否可以诱使脚本读取导致Bash内存不足的大文件,或者读取设备文件(如/dev/random(?当然,任何像这样的配置都会自动意味着用户的输入会影响脚本的后续行为;你需要确保没有任何可能的影响是你认为有害的。


无需进一步操作,以下是函数:

source-assoc-array() {
if [[ "$1" = -- ]] ; then
shift
fi
if [[ "$#" != 1 ]] ; then
echo 'Usage: source-assoc-array ARRAY_NAME < FILE' >&2
return 1
fi
if ! [[ "$(declare -p -- "$1" 2>&1)" == 'declare -A '* ]] ; then
printf '[%s] is not an associative array.n' "$1" >&2
return 1
fi
source <(
perl -w -e '
my $array_name = $ARGV[0];
while (<STDIN>) {
unless (m/^([^=]*)=(.*)$/) {
die "[source-assoc-array] Error on line $.: No equals sign.n";
}
my ($key, $val) = ($1, $2);
unless ($key =~ m/^[A-Za-z_][A-Za-z0-9_]*$/) {
die "[source-assoc-array] Error on line $.: Invalid key.n";
}
if ($val =~ m//) {
die "[source-assoc-array] Error on line $.: Null byte.n";
}
unless ($val =~ m/^(?:[^\]|\[\n])*$/) {
die "[source-assoc-array] Error on line $.: Unescaped backslash.n";
}
$val =~ s/x27/\x27/g; # escape single-quotes
print "$array_name[$key]=$x27$valx27n";
}
' -- "$1" 
|| echo 'return 1'
)
}

最新更新