设置计算环境变量的安全方法

时间:2010-03-22 22:23:35

标签: bash shell environment-variables security

我有一个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)它使用了我之前从未使用过的时髦的外展物,并且(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(全局设置)或正则表达式(仅限bash> = 3)。它的工作原理是抛弃任何不在允许字符的白名单中的内容,然后将结果与原始字符进行比较。如果没有抛出任何内容,那么整个密钥必须只包含列入白名单的字符。

2 个答案:

答案 0 :(得分:0)

一种方法是知道你会得到什么样的讨厌的东西。然后在函数从stdin读取时清理值。例如(bash> 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
 }

答案 1 :(得分:0)

使用declareevalsafer

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