2010-03-22 23 views
2

我有一个bash脚本,我正在修改接受来自stdin的key = value对。 (它由xinetd产生。)我怎样才能安全地将这些key = value对转换为子进程的环境变量?设置计算环境变量的安全方法

我打算只允许以预定义前缀“CMK_”开头的键,以避免IFS或任何其他“危险”变量设置。但简单的做法

function import() 
{ 
    local IFS="=" 
    while read key val; do 
     case "$key" in CMK_*) 
      eval "$key=$val";; 
     esac 
    done 
} 

是可怕的不安全因为$ val可能包含各种讨厌的东西。这似乎是它的工作:

shopt -s extglob 
function import() 
{ 
    NORMAL_IFS="$IFS" 
    local IFS="=" 
    while read key val; do 
     case "$key" in CMK_*([a-zA-Z_])) 
      IFS="$NORMAL_IFS" 
      eval $key='$val' 
      export $key 
      IFS="=" 
      ;; 
     esac 
    done 
} 

,但(1)它使用了我以前从未使用过的时髦extglob的事情,和(2)它的复杂,以至于我不能感到满意,认为它是安全的。

我的目标,具体而言,是允许key = value设置通过bash脚本进入被调用进程的环境。这是由子过程来处理潜在的敌对价值。

我正在修改别人的脚本,所以我不想只将它转换为Perl,并用它来完成。我也宁可不改变它周围的不同调用子进程,像

#!/bin/sh 
...start of script... 
perl -nle '($k,$v)=split(/=/,$_,2); $ENV{$k}=$v if $k =~ /^CMK_/; END { exec("subprocess") }' 
...end of script... 

更新:我结束了使用为重点检查:

if [ "$key" = "${key%[^a-zA-Z_0-9]*}" ]; then 

它不要求extglob(全局设置)或regexes(仅在bash> = 3时)。它通过丢弃任何不在允许字符的白名单中的任何东西,然后将结果与原始字符进行比较。如果什么都没有被抛出,那么整个密钥必须只包含白名单的字符。

回答

0

它更safer使用declareeval

shopt -s extglob 
function import() 
{ 
    NORMAL_IFS="$IFS" 
    local IFS="=" 
    while read key val; do 
     case "$key" in 
      CMK_*([a-zA-Z_])) 
       IFS="$NORMAL_IFS" 
       declare $key="$val" 2>/dev/null || echo "Bad key" 
       IFS="=" # why set this here? 
       ;; 
      *) 
       echo "Bad key" 
       ;; 
     esac 
    done 
} 

如果你不想使用extglob,您可以使用正则表达式匹配测试:

while ... 
if [[ $key =~ CMK_ ]] # or something like: [[ $key =~ CMK_[[:alpha:]] ]] 
then 
    declare ... 
else 
    echo "Bad key" 
fi 

另请参阅this

+0

回复:为什么我要重新设置IFS。在某些情况下,我收到错误“CMK_TEST:找不到命令”,因为它在=符号上分裂。至于什么时候发生,我仍然有点困惑,因为在简单的测试中它不会。 – sfink

+0

我不知道申报。这是一个有用的位。避免评估总是好的。但是我最终使用了避免使用extglob或正则表达式的东西(因此满足了我的秘密议程,即保留在完全由我的任意体验和舒适级别描述的bash的便携式子集中。)我将用我的更新主帖结束了使用。 – sfink

0

一种方法是知道你会得到什么样的讨厌的东西。然后在您的函数从stdin读取时清理该值。如(庆典> 3.2)

function import() 
{ 
    local IFS="=" 
    while read key val; do 
     case "$key" in CMK_*) 
      # you can use case/esac here if you like 
      if [[ $val =~ "some bad stuff" ]] ;then 
       echo "bad stuff found" 
       echo "decide to exit or not here" 
      else 
       eval "$key=$val";; 
      fi 

     esac 
    done 
} 
+2

这让我很紧张。我需要预测所有可能的恶劣东西形式。我宁愿依赖白名单而不是黑名单。 – sfink