Apa masalahnya
Pertama, seperti banyak utilitas, Anda akan memiliki masalah dengan nama file yang dimulai dengan -
. Sementara di:
sh -c 'inline sh script here' other args
Argumen lain diteruskan ke inline sh script
; dengan yang perl
setara,
perl -e 'inline perl script here' other args
Argumen lain dipindai untuk opsi lebih lanjut untuk melakukan perl pertama, bukan ke skrip inline. Jadi, misalnya, jika ada file yang dipanggil -eBEGIN{do something evil}
di direktori saat ini,
perl -ne 'inline perl script here;' *
(dengan atau tanpa -n
) akan melakukan sesuatu yang jahat.
Seperti untuk utilitas lain, pekerjaan untuk itu adalah dengan menggunakan penanda opsi akhir ( --
):
perl -ne 'inline perl script here;' -- *
Tetapi meskipun demikian, itu masih berbahaya dan itu tergantung pada <>
operator yang digunakan oleh -n
/ -p
.
Masalahnya dijelaskan dalam perldoc perlop
dokumentasi.
Itu operator khusus digunakan untuk membaca satu baris (satu catatan, catatan menjadi garis secara default) dari input, di mana input tersebut berasal dari masing-masing argumen pada gilirannya diteruskan @ARGV
.
Di:
perl -pe '' a b
-p
menyiratkan while (<>)
loop di sekitar kode (kosong di sini).
<>
pertama akan membuka a
, membaca catatan satu baris pada satu waktu sampai file habis dan kemudian membuka b
...
Masalahnya adalah, untuk membuka file, ia menggunakan bentuk pertama yang tidak aman dari open
:
open ARGV, "the file as provided"
Dengan bentuk itu, jika argumennya adalah
"> afile"
, itu terbuka afile
dalam mode penulisan,
"cmd|"
, ini berjalan cmd
dan membaca outputnya.
"|cmd"
, Anda memiliki aliran terbuka untuk menulis ke input cmd
.
Jadi misalnya:
perl -pe '' 'uname|'
Tidak menampilkan konten dari file yang disebut uname|
(nama file yang benar-benar valid btw), tetapi output dari uname
perintah.
Jika Anda menjalankan:
perl -ne 'something' -- *
Dan seseorang telah membuat file yang disebut rm -rf "$HOME"|
(lagi nama file yang benar-benar valid) di direktori saat ini (misalnya karena direktori itu pernah ditulisi oleh orang lain, atau Anda telah mengekstrak arsip yang cerdik, atau Anda telah menjalankan beberapa perintah yang cerdik, atau Kerentanan lain dalam beberapa perangkat lunak lain dieksploitasi), maka Anda dalam masalah besar. Area di mana penting untuk mengetahui masalah itu adalah alat yang memproses file secara otomatis di tempat umum area seperti /tmp
(atau alat yang dapat disebut dengan alat tersebut).
File yang disebut > foo
, foo|
, |foo
adalah masalah. Tetapi pada tingkat lebih rendah < foo
danfoo
dengan karakter spasi ASCII memimpin atau mengikuti (termasuk spasi, tab, baris baru, cr ...) serta itu berarti file-file itu tidak akan diproses atau yang salah akan.
Juga berhati-hatilah bahwa beberapa karakter dalam beberapa set karakter multi-byte (seperti ǖ
dalam BIG5-HKSCS) berakhir pada byte 0x7c, yang merupakan pengkodean dari |
.
$ printf ǖ | iconv -t BIG5-HKSCS | od -tx1 -tc
0000000 88 7c
210 |
0000002
Jadi di lokal menggunakan charset itu,
perl -pe '' ./nǖ
Akan mencoba menjalankan ./n\x88
perintah karena tidakperl
akan mencoba menafsirkan nama file di lokal pengguna!
Bagaimana cara memperbaikinya?
AFAIK, tidak ada yang dapat Anda lakukan untuk mengubah perilaku default yang tidak aman itu perl
untuk semua sistem.
Pertama, masalah terjadi hanya dengan karakter di awal dan akhir nama file. Jadi, sementara perl -ne '' *
atau perl -ne '' *.txt
masalah,
perl -ne 'some code' ./*.txt
tidak karena semua argumen sekarang mulai dengan ./
dan akhir di .txt
(jadi tidak -
, <
, >
, |
, ruang ...). Secara umum, ini adalah ide yang baik untuk awalan dengan gumpalan./
. Itu juga menghindari masalah dengan file yang dipanggil -
atau mulai dengan -
banyak utilitas lain (dan di sini, itu berarti Anda tidak memerlukan --
penanda opsi-akhir ( ) lagi).
Menggunakan -T
untuk mengaktifkan taint
mode membantu sampai batas tertentu. Ini akan membatalkan perintah jika file berbahaya tersebut ditemukan (hanya untuk >
dan |
kasus, bukan <
atau spasi putih sekalipun).
Itu berguna ketika menggunakan perintah seperti itu secara interaktif yang memperingatkan Anda bahwa ada sesuatu yang cerdik terjadi. Itu mungkin tidak diinginkan ketika melakukan beberapa pemrosesan otomatis, karena itu berarti seseorang dapat membuat pemrosesan itu gagal hanya dengan membuat file.
Jika Anda ingin memproses setiap file, terlepas dari nama mereka, Anda dapat menggunakan yang ARGV::readonly
perl
modul CPAN (sayangnya biasanya tidak terinstal secara default). Itu adalah modul yang sangat singkat:
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
};
};
Pada dasarnya, itu membersihkan @ ARGV dengan mengubah " foo|"
misalnya menjadi "< ./ foo|\0"
.
Anda dapat melakukan hal yang sama dalam BEGIN
pernyataan di perl -n/-p
perintah Anda :
perl -pe 'BEGIN{$_.="\0" for @ARGV} your code here' ./*
Di sini kita menyederhanakannya dengan asumsi itu ./
sedang digunakan.
Efek samping dari itu (dan ARGV::readonly
) adalah bahwa $ARGV
dalamyour code here
menunjukkan bahwa karakter NUL tertinggal.
Perbarui 2015-06-03
perl
v5.21.5 dan di atasnya memiliki <<>>
operator baru yang berperilaku seperti <>
kecuali bahwa itu tidak akan melakukan pemrosesan khusus. Argumen hanya akan dianggap sebagai nama file. Jadi dengan versi-versi itu, Anda sekarang dapat menulis:
perl -e 'while(<<>>){ ...;}' -- *
(jangan lupa --
atau gunakan ./*
meskipun) tanpa takut akan menimpa file atau menjalankan perintah yang tidak terduga.
-n
Saya -p
masih menggunakan <>
bentuk berbahaya sekalipun. Dan berhati-hatilah symlink masih diikuti, sehingga tidak berarti aman untuk digunakan di direktori yang tidak terpercaya.
Selain jawaban @ Stéphane Chazelas , kami tidak perlu khawatir tentang masalah ini jika menggunakan
-i
opsi baris perintah:Karena ketika menggunakan
-i
opsi,perl
gunakan stat untuk memeriksa status file sebelum memprosesnya:sumber
stat
cek dan pemrosesan perl yang efektif terjadi setelahnya?stat
. Hanya saja-i
untuk mengedit file di tempat, jadi tidak masuk akal untuk menerima argumen selain jalur file yang sebenarnya, jadi dengan itu-i
, pemrosesan khusus tidak dilakukan.