安全bash配置文件

时间:2020-03-03 12:51:55

标签: bash

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

我想提供一种安全可靠的解决方案。

  • [健壮]:不要尝试使用正则表达式太聪明(和容易出错)

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

touch your_computer_is_hacked
foo=bar

配置文件的最佳做法是什么? 所以我可以将所有值都放在一个关联数组中吗?我不在乎实际的格式(bash脚本,yaml,ini,xml,javascript),但是应该完全指定它,因此如果我想添加空格/换行符或ő字符对于foo变量,应指定操作方法。

1 个答案:

答案 0 :(得分:0)

我认为您最好的选择是编写source <(...),其中...是从标准输入中读取并写出所需映射的命令。这样,...可以是Perl脚本,Python脚本或其他任何东西,这比在纯Bash中执行此操作容易。

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

  • 每行一次分配。没有空行,没有注释行,没有跨越多行的分配,除了分配以外没有其他命令。
  • 每个分配采用key=value的形式。不允许使用空格,当然value可以包含空格。
  • 键是一个或多个ASCII字母,数字和下划线,不能以数字开头。 (这些是Bash变量名的规则。)
  • 该值是零个或多个非空字节。 (Bash words can't contain null bytes,所以这是不可避免的限制。)换行符表示为\n;反斜杠表示为\\;所有其他字节均表示为自己。
  • 例如,如果foo='bar\n\\\nbaz'是关联数组的名称,则将行arr[foo]=$'\'bar\n\\\nbaz\''转换为arr
  • 如果遇到不符合上述规则的任何行,该函数将以错误消息中止。

您可以通过支持各种功能(例如空行,注释,前导和尾随空格(包括尾随回车符,以支持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/\0/) {
          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$val\x27\n";
      }
    ' -- "$1" \
    || echo 'return 1'
  )
}