Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
546 views
in Technique[技术] by (71.8m points)

regex - Using the ee modifier safely with the s/// operator when the right side is input from user

I am writing a Perl script where the user can input a regex and a replacement string. The script will search a set of files and apply changes according the perl s/// operator applied with the user input.

To complicate matters slightly, the replacement string is allowed to contain backreferences to refer to capture groups in the regex. For example, if the regex is b(.*?)a and the replacement string is a$1b the $1 should not be treated literally, but rater as a backreference to capture group number one.

In this setting, I am wondering if it is possible to use the ee modifier (to evaluate the backreferences in the user input) safely with the s/// operator when the right hand side of this operator is input by the user? For example:

use strict;
use warnings;
my $str = 'abaaca';

my $replacement = 'do{ use Env qw(HOME); unlink "$HOME/important.txt" }';

$str =~ s/a(.*?)a/$replacement/gee;

would be unfortunate.. But then I got the idea to quote the user input (put it inside a pair of double quotes) after having escaped double quotes and dollar signs (not followed by a number), and then do replacement:

use feature qw(say);
use strict;
use warnings;

my $str = 'abaaca';

my $replacement = shift;
$replacement =~ s/"/"/g;
$replacement =~ s/$(?!d)/\$/g;
$replacement = '"' . $replacement . '"';
$str =~ s/a(.*?)a/$replacement/gee;
say $str;

To me this seems to work at first glance, or have I missed something? For example if the script is called test.pl and the user runs it as:

$ test.pl 'do{ "a$b" }'

the output is as desired just a simple string ( and no code is evaluated ):

do{ "a$b" }do{ "a$b" }

So the question is: Is this really a safe/correct approach?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Problem 1:

There's no way to replace with $1 followed by 1 since the following replaces with ${1}1.

$ script '${1}1'
${1}1${1}1

Problem 2:

$ script '${ system "echo rm -rf /" }'
rm -rf /
Use of uninitialized value in substitution iterator at a.pl line 12.
rm -rf /
Use of uninitialized value in substitution iterator at a.pl line 12.

Problem 3:

$ script '$1{ system "echo rm -rf /" }'
rm -rf /
Use of uninitialized value within %1 in string at (eval 1) line 1.
rm -rf /
Use of uninitialized value within %1 in string at (eval 2) line 1.

Surely, there are others. Solution:

Use String::Substitution.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...