2015-03-17 1 views
5

Ich schreibe ein Perl-Skript, wo der Benutzer eine Regex und eine Ersatzzeichenfolge eingeben kann. Das Skript durchsucht eine Reihe von Dateien und wendet Änderungen entsprechend dem Perl-Operator s/// an, der mit der Benutzereingabe angewendet wurde.Den ee-Modifizierer sicher mit dem Operator s /// verwenden, wenn die rechte Seite vom Benutzer eingegeben wird

Um die Angelegenheit leicht zu komplizieren, darf die Ersetzungszeichenfolge Rückreferenzen enthalten, um auf Erfassungsgruppen in der Regex zu verweisen. Wenn die Regex beispielsweise b(.*?)a lautet und die Ersetzungszeichenfolge a$1b lautet, sollte die $1 nicht wörtlich behandelt werden, sondern eher als Rückreferenz, um die erste Gruppe zu erfassen.

In dieser Einstellung, ich frage mich, ob es möglich ist, den ee Verwendung des Änderungs sicher mit dem s/// Operator (die Rückreferenzierungen in der Benutzereingabe zu bewerten), wenn die rechte Seite dieses Operators Eingabe durch den Benutzer ist? Zum Beispiel:

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

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

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

würde unglücklich sein .. Aber dann bekam ich die Idee, die Benutzereingabe zu zitieren (legt es in einem Paar doppelter Anführungszeichen) nach entkam doppelten Anführungszeichen und Dollar-Zeichen (nicht mit einer Nummer) und dann tun Ersatz:

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; 

Für mich auf den ersten Blick scheint zu funktionieren, oder habe ich etwas verpasst? Zum Beispiel, wenn das Skript test.pl genannt, und der Benutzer läuft es wie:

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

der Ausgang nur eine einfache Zeichenfolge wie gewünscht (und kein Code ausgewertet wird):

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

Die Frage ist also: Ist das wirklich ein sicherer/korrekter Ansatz?

+0

Wenn der Benutzer Ihr Skript einfach auf einem Computer ausführt, auf den er bereits Zugriff hat, warum konnten sie es dann nicht einfach bearbeiten, um die bösen Dinge zu tun, die sie wollten? Oder schreiben Sie ihr eigenes Perl-Skript, das böse Dinge tut? – ThisSuitIsBlackNot

+0

Sicher, das ist ein guter Punkt .. aber ich habe über den Fall nachgedacht, wo der Benutzer zufällig etwas eintippte, was dazu führte, dass Code im 's ///' Operator ausgeführt wurde.und das könnte unerwünschte Folgen haben –

Antwort

5

Problem 1:

Es gibt keine Möglichkeit, mit $1 von 1, da der folgenden Text ersetzt mit ${1}1 gefolgt zu ersetzen.

$ 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. 

Sicher, es gibt auch andere. Lösung:

Verwenden Sie String::Substitution.

+0

Danke, das sieht gut aus. Scheint, als ob jemand mein Problem bereits gelöst hat. –

+0

Wie funktioniert eigentlich Problem 2? Wenn ich 'script '$ 1 {say" "}'' erstelle ich einen Fehler 'Verwendung von nicht initialisierten Wert innerhalb% 1 in der Zeichenfolge in (eval 1) Zeile 1.' Ich bin hier fest, warum bekomme ich diesen Fehler Nachricht, und warum sagt es '% 1'? –

+0

Vielleicht, wenn Sie etwas anderes als leere Zeile gedruckt, wäre es auffälliger, dass Sie etwas gedruckt ... – ikegami

Verwandte Themen