Regex 如何验证Perl CGI脚本的输入,以便安全地将其传递给shell?
我对Perl和复杂的正则表达式都是新手。我的意思是我以前用过正则表达式中的*,但没有比这更复杂的了。在下面的脚本中,我知道有一个非常大的安全漏洞,在这个漏洞中可以注入并运行perl代码,这样即使是一个shell也可以执行任何命令。在试图阻止这种注入时,我逐渐意识到正则表达式比我想象的要困难得多。我正在使用的书说使用Regex 如何验证Perl CGI脚本的输入,以便安全地将其传递给shell?,regex,perl,security,cgi,Regex,Perl,Security,Cgi,我对Perl和复杂的正则表达式都是新手。我的意思是我以前用过正则表达式中的*,但没有比这更复杂的了。在下面的脚本中,我知道有一个非常大的安全漏洞,在这个漏洞中可以注入并运行perl代码,这样即使是一个shell也可以执行任何命令。在试图阻止这种注入时,我逐渐意识到正则表达式比我想象的要困难得多。我正在使用的书说使用 die "The specified user contains illegal characters!" unless($user =~/^\w+$/); 我相当确定
die "The specified user contains illegal characters!"
unless($user =~/^\w+$/);
我相当确定这意味着用户的输入必须以多个单词开头,但我不确定这如何阻止命令被注入,因为它从不检查分号。我认为除非条款应该更像
unless($user=~/^\w+;\w$/);
然而,两者似乎都不起作用。这方面的任何帮助都会很棒,因为我真的很想理解这一点。
谢谢
#/usr/bin/perl
使用CGI;
使用CGI::Carp qw(fatalsToBrowser);
$q=新的CGI;
打印$q->标题,
$q->start_html('Finger User'),
$q->h1(“手指用户”),
打印“”;
$user=$q->param(“用户”);
#“指定的用户包含非法字符!”
#除非($user=~/ls/);
如果(!($user=~/^\w*;\w*$/){
打印“/usr/bin/finger-s$user”;
}
打印“”;
打印$q->end\u html;
\w
只匹配一个字符,而不是一个单词。在ASCII格式中,它是[A-Za-z0-9.]
之一
\w+
匹配上述一个或多个字符,例如,a_b0c
^
和$
确保$user
字符串中没有其他内容
因此,如果$user
仅包含字母数字字符和下划线,而不包含其他内容,则$user=~/^\w+$/
为真。如果条件为false,程序将终止
$
也可以在字符串末尾的换行符之前匹配。如果$user
可能以换行符结尾,并且您希望拒绝此类情况,则可以使用\z
而不是$
\z
仅在字符串末尾匹配。\w
匹配单个字符,而不是一个单词。在ASCII格式中,它是[A-Za-z0-9.]
之一
\w+
匹配上述一个或多个字符,例如,a_b0c
^
和$
确保$user
字符串中没有其他内容
因此,如果$user
仅包含字母数字字符和下划线,而不包含其他内容,则$user=~/^\w+$/
为真。如果条件为false,程序将终止
$
也可以在字符串末尾的换行符之前匹配。如果$user
可能以换行符结尾,并且您希望拒绝此类情况,则可以使用\z
而不是$
<代码>\z仅在字符串末尾匹配。这里还有一个重要的点。在编写代码时,除了两个由一个分号分隔的字母数字序列之外,您的代码将允许其他任何内容。例如alice;回声“破碎!”;bob
是一个完全有效的程序输入,因为它包含两个分号和一些其他非字母数字字符
这里的一般原则是,您通常应该测试并只接受“好”输入,而不是拒绝“坏”输入。这是许多关于这个主题的好文章之一。这里还有一个重要的观点。在编写代码时,除了两个由一个分号分隔的字母数字序列之外,您的代码将允许其他任何内容。例如
alice;回声“破碎!”;bob
是一个完全有效的程序输入,因为它包含两个分号和一些其他非字母数字字符
这里的一般原则是,您通常应该测试并只接受“好”输入,而不是拒绝“坏”输入。是许多关于这个主题的好文章之一。首先,让我们看看给你带来麻烦的陈述:
if ( $user !~ /^\w+$/ ) {
die "...";
}
这是另一种写作方式:
^ the beginning of the string
\w+ one or more word characters
$ before an optional \n, and the end of the
string
因此,在获得更广泛的接受之前,如果您只想匹配这些字符,最安全的做法是明确地说[a-z_a-Z0-9]
$user=~/^\w+\w$/
考虑到上面的讨论,现在应该很清楚
$user=~/^\w+\w$/
将只匹配包含单词字符的输入,a
分号和尾随字字符,可能还有换行符
至于你的密码
use strict;
use warnings;
首先,你失踪了
$q = new CGI;
如果你想拯救你自己,也可能拯救其他人,这些pragma是而不是可选的
这个世界有些令人头痛
其次,使用CGI::Carp qw(fatalsToBrowser)代码>应仅用作
如果您没有访问web服务器日志的权限,则为短期抓取
第三,
my $q = CGI->new;
应该是
print $q->header,
$q->start_html('Finger User'),
$q->h1('Finger User'),
print "<pre>";
新的CGI
被称为间接对象表示法,让您任由
perl
关于您的代码最终会做什么<代码>CGI->new
明确地调用
CGI
提供的新方法。另外,我讨厌$q
或$query
作为
包含CGI
对象的变量的名称。只需一个简单的$cgi
就可以了
有意义
最后,看看:
#!/usr/bin/env perl
use strict;
use warnings;
use CGI::Simple;
use HTML::Template;
run();
sub run {
my $cgi = CGI::Simple->new;
my $tmpl = HTML::Template->new(filehandle => \*DATA);
my $user = $cgi->param('finger_user');
unless (defined $user) {
show_form($cgi, $tmpl);
return;
}
if (($user) = ($user =~ /^([A-Z_a-z0-9]{1,40})\z/)) {
show_output($cgi, $tmpl, $user);
}
else {
show_error($cgi, $tmpl, "Invalid user name");
}
return;
}
sub show_form {
my ($cgi, $tmpl) = @_;
$tmpl->param(FORM => 1);
print $cgi->header(
-type => 'text/html',
-charset => 'utf-8',
), $tmpl->output;
return;
}
sub show_error {
my ($cgi, $tmpl, $msg) = @_;
$tmpl->param(ERRORMSG => $msg);
print $cgi->header(
-type => 'text/html',
-charset => 'utf-8',
), $tmpl->output;
return;
}
sub show_output {
my ($cgi, $tmpl, $user) = @_;
$tmpl->param(
USER => $user,
OUTPUT => scalar `finger -s $user`,
);
print $cgi->header(
-type => 'text/html',
-charset => 'utf-8',
), $tmpl->output;
return;
}
__DATA__
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>finger
<TMPL_IF USER>
<TMPL_VAR USER>
<TMPL_ELSE>
a user
</TMPL_IF>
on our system</title>
</head>
<body>
<TMPL_IF ERRORMSG>
<p syle="color:#e11"><TMPL_VAR ERRORMSG></p>
</TMPL_IF>
<TMPL_IF OUTPUT>
<h1>finger <TMPL_VAR USER></h1>
<pre><TMPL_VAR OUTPUT></pre>
</TMPL_IF>
<TMPL_IF FORM>
<form id="finger_form" name="finger_form" method="GET">
<p><label for="finger_user"><input id="finger_user" name="finger_user" type="text"
size="51"><input type="submit" value="finger" id="finger_submit"
name="finger_submit"></p>
</form>
</TMPL_IF>
</body>
</html>
首先,让我们看看给您带来麻烦的陈述:
if ( $user !~ /^\w+$/ ) {
die "...";
}
这是另一种写作方式:
^ the beginning of the string
\w+ one or more word characters
$ before an optional \n, and the end of the
string
因此,在获得更广泛的接受之前,如果您只想匹配这些字符,最安全的做法是明确地说[a-z_a-Z0-9]
$user=~/^\w+\w$/
考虑到上面的讨论,现在应该很清楚
$user=~/^\w+\w$/
将只匹配包含单词字符的输入,a
分号和尾随字字符,可能还有换行符
至于你的密码
use strict;
use warnings;
首先,你失踪了
$q = new CGI;
如果你想拯救你自己,也可能拯救其他人,这些pragma是而不是可选的
这个世界有些令人头痛
<