Was ist das Problem
Erstens, wie bei vielen Dienstprogrammen, treten Probleme mit Dateinamen auf, die mit beginnen -
. Während in:
sh -c 'inline sh script here' other args
Die anderen Argumente werden an die weitergereicht inline sh script
; mit dem perl
Äquivalent,
perl -e 'inline perl script here' other args
Die anderen Argumente werden nach weiteren Optionen durchsucht, um zuerst Perl und nicht das Inline-Skript zu verwenden. Wenn sich also beispielsweise eine Datei -eBEGIN{do something evil}
im aktuellen Verzeichnis befindet,
perl -ne 'inline perl script here;' *
(mit oder ohne -n
) wird etwas Böses tun.
Wie bei anderen Dienstprogrammen besteht die Lösung darin, die Option zum Beenden der Optionen ( --
) zu verwenden:
perl -ne 'inline perl script here;' -- *
Aber selbst dann ist es immer noch gefährlich und das liegt an dem <>
Operator, der von -n
/ verwendet wird -p
.
Das Problem wird in der perldoc perlop
Dokumentation erläutert .
Dieser spezielle Operator wird verwendet, um eine Zeile (ein Datensatz, wobei die Datensätze standardmäßig Zeilen sind) der Eingabe zu lesen, wobei diese Eingabe von jedem der nacheinander übergebenen Argumente stammt @ARGV
.
Im:
perl -pe '' a b
-p
impliziert eine while (<>)
Schleife um den Code (hier leer).
<>
wird zuerst geöffnet a
, liest die Datensätze zeilenweise, bis die Datei erschöpft ist, und öffnet dann b
...
Das Problem ist, dass zum Öffnen der Datei die erste unsichere Form verwendet wird open
:
open ARGV, "the file as provided"
Mit diesem Formular, wenn das Argument ist
"> afile"
, es öffnet sich afile
im Schreibmodus,
"cmd|"
, es läuft cmd
und liest seine Ausgabe.
"|cmd"
, du hast einen Stream zum Schreiben für den Eingang von geöffnet cmd
.
Also zum Beispiel:
perl -pe '' 'uname|'
Gibt nicht den Inhalt der aufgerufenen Datei aus uname|
(übrigens einen vollkommen gültigen Dateinamen), sondern die Ausgabe des uname
Befehls.
Wenn du rennst:
perl -ne 'something' -- *
Und jemand hat rm -rf "$HOME"|
im aktuellen Verzeichnis eine Datei mit dem Namen (wieder ein vollkommen gültiger Dateiname) erstellt (zum Beispiel, weil dieses Verzeichnis einmal von anderen geschrieben werden konnte oder weil Sie ein zweifelhaftes Archiv extrahiert oder einen zweifelhaften Befehl ausgeführt haben oder Eine andere Sicherheitslücke in einer anderen Software wurde ausgenutzt. Bereiche, in denen es wichtig ist, sich dieses Problems bewusst zu sein, sind Tools, die Dateien automatisch in öffentlichen Bereichen verarbeiten /tmp
(oder Tools, die möglicherweise von solchen Tools aufgerufen werden).
Dateien genannt > foo
, foo|
, |foo
sind ein Problem. In geringerem Umfang < foo
und foo
mit führenden oder nachfolgenden ASCII-Abständen (einschließlich Leerzeichen, Tabulatoren, Zeilenumbrüchen, Zeilenumbrüchen usw.) bedeutet dies jedoch, dass diese Dateien nicht verarbeitet werden oder dass die falschen verarbeitet werden.
Beachten Sie auch, dass einige Zeichen in einigen ǖ
Mehrbyte- Zeichensätzen (wie in BIG5-HKSCS) in Byte 0x7c enden, der Kodierung von |
.
$ printf ǖ | iconv -t BIG5-HKSCS | od -tx1 -tc
0000000 88 7c
210 |
0000002
Also in Gebietsschemas mit diesem Zeichensatz,
perl -pe '' ./nǖ
Versuchen würde , den laufen ./n\x88
Befehl als perl
würde nicht , dass die Dateinamen des Gebietsschema des Benutzers zu interpretieren versuchen!
Wie zu beheben / umgehen
AFAIK, Sie können nichts tun, um dieses unsichere Standardverhalten perl
ein für alle Mal systemweit zu ändern .
Erstens tritt das Problem nur bei Zeichen am Anfang und Ende des Dateinamens auf. Also, während perl -ne '' *
oder perl -ne '' *.txt
sind ein Problem,
perl -ne 'some code' ./*.txt
nicht , weil alle jetzt die Argumente mit Start ./
und Ende in .txt
(also nicht -
, <
, >
, |
, Raum ...). Allgemeiner gesagt , ist es eine gute Idee, Präfix Klackse mit ./
. Das vermeidet auch Probleme mit Dateien, die aufgerufen werden -
oder -
mit vielen anderen Dienstprogrammen beginnen (und hier bedeutet dies, dass Sie den End-of-options ( --
) -Marker nicht mehr benötigen ).
Das -T
Einschalten des taint
Modus hilft in gewissem Maße. Der Befehl wird abgebrochen, wenn eine solche schädliche Datei gefunden wird (nur für die Fälle >
und |
, jedoch nicht für <
Leerzeichen).
Dies ist nützlich, wenn Sie solche Befehle interaktiv verwenden, da Sie dadurch darauf hingewiesen werden, dass etwas Ungewöhnliches vor sich geht. Dies ist jedoch möglicherweise nicht wünschenswert, wenn eine automatische Verarbeitung durchgeführt wird, da dies bedeutet, dass eine andere Person diese Verarbeitung nur durch das Erstellen einer Datei zum Scheitern bringen kann.
Wenn Sie jede Datei unabhängig von ihrem Namen verarbeiten möchten, können Sie das ARGV::readonly
perl
Modul auf CPAN verwenden (leider normalerweise nicht standardmäßig installiert). Das ist ein sehr kurzes Modul, das Folgendes bewirkt:
sub import{
# Tom Christiansen in Message-ID: <24692.1217339882@chthon>
# reccomends essentially the following:
for (@ARGV){
s/^(\s+)/.\/$1/; # leading whitespace preserved
s/^/< /; # force open for input
$_.=qq/\0/; # trailing whitespace preserved & pipes forbidden
};
};
Im Grunde desinfiziert es @ARGV, indem es sich " foo|"
zum Beispiel in "< ./ foo|\0"
.
Sie können dasselbe in einer BEGIN
Anweisung in Ihrem perl -n/-p
Befehl tun :
perl -pe 'BEGIN{$_.="\0" for @ARGV} your code here' ./*
Hier vereinfachen wir es unter der Annahme, ./
dass verwendet wird.
Ein Nebeneffekt dieses (und ARGV::readonly
) ist jedoch, dass $ARGV
in your code here
dieses nachgestellte NUL-Zeichen zeigt.
Update 03.06.2015
perl
v5.21.5 und höher haben einen neuen <<>>
Operator, der sich so verhält, <>
außer dass er diese spezielle Verarbeitung nicht ausführt . Argumente werden nur als Dateinamen betrachtet. Mit diesen Versionen können Sie nun schreiben:
perl -e 'while(<<>>){ ...;}' -- *
(Vergiss das nicht --
oder benutze es ./*
), ohne befürchten zu müssen, dass es Dateien überschreibt oder unerwartete Befehle ausführt.
-n
/ -p
Noch die gefährliche verwenden <>
Form though. Beachten Sie, dass Symlinks weiterhin befolgt werden, was nicht unbedingt bedeutet, dass die Verwendung in nicht vertrauenswürdigen Verzeichnissen sicher ist.
Zusätzlich zur Antwort von @ Stéphane Chazelas müssen wir uns um dieses Problem keine Sorgen machen, wenn wir die
-i
Befehlszeilenoption verwenden:Denn wenn Sie die
-i
Option verwenden, haben Sieperl
mit stat den Dateistatus überprüft, bevor Sie ihn verarbeiten:quelle
stat
Check und der effektiven Perl-Verarbeitung, die unmittelbar danach stattfindet?stat
. Es ist nur so, dass Dateien an Ort und Stelle-i
bearbeitet werden. Daher ist es nicht sinnvoll, andere Argumente als die tatsächlichen Dateipfade zu akzeptieren, sodass keine-i
spezielle Verarbeitung erfolgt.