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 与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…