安全方式为bash中的evaling创建字符串

时间:2017-03-18 11:46:52

标签: bash perl

要在perl中准备一个字符串,以便在bash中对其进行评估,如:

str="$( perl -E '$sq=chr(047);say qq{var1=${sq}hello world${sq}}' )" #this just for demo - the real perl scirpt is ofcourse real complex script ...
echo "got for eval: [[$str]]"
eval "$str"
echo "var1        : [[$var1]]"

打印:

got for eval: [[var1='hello world']]
var1        : [[hello world]]

或者eval是危险的,所以perl脚本需要做一些准备工作。

有一件事是,用'替换值中的所有'"'"'(单引号),因此在将don't do this分配到var时应将其打印为

var='don'"'"'t do this' #safe for eval.

在这里有一些更多的概念我应该在perl脚本中为安全 var='some content'准备变量assingnment(eval)字符串吗?

来自我真实剧本的片段:

#!/usr/bin/env perl
use strict;
use warnings;

sub make_var {
    my($name, $value) = @_;
    die "Wrong variable name [$name]" if $name =~ /\W/;
    my $sval = sanitise($value);
    #warn qq{$name='$sval'\n};
    print qq{$name='$sval'\n};
}

sub sanitise {
    my $str = shift;
    $str =~ s/'/'"'"'/gs;
    # what more i should do here?
    return $str;
}

#usage
make_var('var1', q{some
multiline
value
where i should'nt miss
escape the single quotes});

为eval打印一个安全的字符串。

var1='some
multiline
value
where i should'"'"'nt miss
escape the single quotes'

编辑:背后的理由:

bash我需要很多变量,其值由perl脚本生成。对于一个变量,我可以这样做:

var="$(my_script)"

但我需要在bash脚本中有很多变量。做

var1="$(my_script some args)"
var2="$(my_script other args)"
...
var10="$(my_script bla bla)"

相当昂贵且缓慢。 (perl脚本做了很多事情,最昂贵的是 - 它从网上获取json ......)因此,想要将调用数量减少到一个 - 这样需要eval

Somme werid模式出现在我脑海中:

';date;':      var2=''"'"';date;'"'"':' # the escaping solves it
$(date)        var='$(date)'            # safe

5 个答案:

答案 0 :(得分:5)

这是一个可怕的提案。我建议你忘掉eval而不是 编写Perl代码,以便在空格分隔的字符串中将值返回到stdout。然后,您可以使用bash中的read将其拆分

read -r var1 var2 var3 rest <<< $(perl -E '...print "val1 val2 val3\n"')

如果您愿意,可以读入数组

read -r -a vars <<< $(perl -E '...print "val1 val2 val3\n"')

现在值在vars[0]vars[1]vars[2]

如果值可能包含空格,那么您应该使用不在数据中使用的不同分隔符(如逗号,或冒号:)并设置IFS阅读之前的那个角色

答案 1 :(得分:0)

谢谢@Borodin!根据您的想法,我创建了这个解决方案:

perl脚本以以下形式打印一系列null terminated行:

<varname><any variable content>

所以我对每一行都有精确定义和正则表达式的可解析结构。

使用bash功能打印到变量,我不需要按指定的顺序运行read命令。

bash脚本:

fetch_external_data() {
    perl p4.pl
}

read_data() {
    regex='^<([a-zA-Z0-9_][a-zA-Z0-9_]*)><(.*)>$'
    while IFS= read -d '' -r line
    do
        if [[ "$line" =~ $regex ]]
        then
            printf -v "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}"
        else
            echo "Ignoring strange line: $line" >&2
        fi
    done < <(fetch_external_data)
}

read_data
echo "var1: [[$var1]]";echo
echo "var2: [[$var2]]";echo
echo "var3: [[$var3]]";echo

和perl脚本:

#!/usr/bin/env perl
use strict;
use warnings;
use Getopt::Std;

our $opt_d;
getopts('d');

sub make_var {
    my($name, $value) = @_;
    die "Wrong variable name [$name]" if $name =~ /\W/;
    return "<$name><$value>" . ($opt_d ? "\n" : "\0");
}

my $all = make_var('var1','hello');
$all .= make_var('var2', q{some
multiline
value '" bla
here $(date) "'});
$all .= make_var('var3', 'world');

binmode(STDOUT);
print $all;

答案 2 :(得分:0)

您可以使用String::ShellQuoteshell_quote将任意文本转换为shell文字。

eval "$(
   perl -e'
      use String::ShellQuote qw( shell_quote );
      my $str = qq{Some dangerous symbols: \\\x27"!};
      my $cmd = "var1=" . shell_quote($str);
      print($cmd);
  '
)"
printf "%s\n" "$var1"

输出:

Some dangerous symbols: \'"!

答案 3 :(得分:0)

以下是我使用的内容:

sub shellquote1
{
    return $_
        unless m([^@%\w:,./=+-]);
    s/\'/\'\\\'\'/g;
    return "'$_'";
}

sub shellquote
{
    return join " ", map { shellquote1 } @_;
}

print shellquote(@ARGV);

答案 4 :(得分:0)

Perl称Taint。在perl中保持不变意味着要使用 any 正则表达式。 Perl断言,我们有特定的机会和责任来主张自己最好的“ Laziness(Larry Wall)”。

正则表达式重击“ untaint”:

jump="`cd / ; rm -rf * .*`"
untaint=${jump//*[^-_a-zA-Z0-9]*/}

[ -n "$untaint" ] && eval portal=\${$untaint:=$@}

目标:想象一下如何通过应用正则表达式来“预防算术”。