Dalam bahasa pemrograman, saya menjalankan perintah shell sederhana
cd var; echo > create_a_file_here
dengan var menjadi variabel yang berisi string (semoga) direktori ke tempat di mana saya ingin membuat file "create_a_file_here". Sekarang jika seseorang melihat baris kode ini, dimungkinkan untuk mengeksploitasinya dengan menetapkan misalnya:
var = "; rm -rf /"
Segalanya bisa menjadi sangat jelek. Salah satu cara untuk menghindari kasus di atas adalah mungkin mencari string dalam var untuk beberapa karakter khusus seperti ';' sebelum menjalankan perintah shell, tetapi saya ragu ini mencakup semua kemungkinan exploit.
Adakah yang tahu cara yang baik untuk memastikan bahwa "cd var" hanya mengubah direktori dan tidak ada yang lain?
shell-script
shell
ES___
sumber
sumber
var
argumen. Misalnya memanggilsh
dengan argumen-c
,'cd "$1"; echo > create_a_file_here'
,'sh'
,var
karya dan tidak perlu perubahan apapunvar
. The'sh'
argumen dilewatkan sebagai$0
.sh
, atau membuat bahasa pemrograman Anda sendiri dengan sintaksis yang sama tetapi yang berkembangvar
bukannya mengharuskan Anda untuk menuliscd "$var"
? Ataubash
dengan inishopt -s cdable_vars
? Oh, saya pikir maksud Anda beberapa program lain menggunakan shell untuk menjalankan perintah ini. Jadivar
, kutip saja , tapi pastikan itu tidak termasuk karakter kutipan sendiri ...s='"'; echo "$s"
cetak"
.var=untrusted string
di program induk, demikianvar
juga variabel lingkungan yang sudah ditetapkan saat memohonsh
. Maka Anda hanya perlu mengutipnya setiap kali Anda mengembangkannya, yang mungkin dilakukan dengan andal. Ah, saya melihat bahwa ide itu sudah menjadi bagian dari jawaban Stéphane>. <Jawaban:
Jika saya mengerti benar,
var
adalah variabel dalam bahasa pemrograman Anda.Dan dalam bahasa pemrograman Anda, Anda meminta shell untuk menafsirkan string yang merupakan gabungan dari
"cd "
, isi dari variabel itu dan"; echo > create_a_file_here"
.Jika demikian, ya, jika konten
var
tidak dikontrol dengan ketat, ini adalah kerentanan injeksi perintah.Anda dapat mencoba dan mengutip dengan benar konten variabel¹ dalam sintaksis shell sehingga dijamin akan diteruskan sebagai argumen tunggal ke
cd
builtin.Pendekatan lain adalah dengan melewatkan konten variabel itu dengan cara lain. Cara yang jelas adalah dengan melewatkannya dalam variabel lingkungan. Misalnya, dalam C:
Kali ini, kode yang Anda minta untuk ditafsirkan oleh shell sudah diperbaiki, kami masih perlu menuliskannya dengan benar di sintaksis shell (di sini diasumsikan sebagai shell yang sesuai dengan POSIX):
-P
untukcd
melakukan sederhanachdir()
--
menandai akhir opsi untuk menghindari masalah denganvar
memulai dengan-
(atau+
dalam beberapa shell)CDPATH
ke string kosong jika itu di lingkunganecho
perintah jikacd
berhasil.Ada (setidaknya) satu masalah yang tersisa: jika
var
adalah-
, tidak melakukan chdir ke direktori yang disebut-
tapi dengan sebelumnya direktori (yang disimpan dalam$OLDPWD
) danOLDPWD=- CDPATH= cd -P -- "$DIR"
tidak dijamin untuk bekerja di sekitarnya. Jadi Anda akan membutuhkan sesuatu seperti:¹ Perhatikan bahwa hanya melakukan
adalah tidak cara untuk pergi, Anda akan hanya bergerak masalah.system(concat("cd \"", var, "\"; echo..."));
Misalnya,
var = "$(rm -rf /)"
masih akan menjadi masalah.Satu- satunya cara yang dapat diandalkan untuk mengutip teks untuk cangkang mirip Bourne adalah dengan menggunakan tanda kutip tunggal dan juga mengurus tanda kutip tunggal yang mungkin terjadi dalam string. Misalnya, mengubah
char *var = "ab'cd"
kechar *escaped_var = "'ab'\\''cd'"
. Artinya, ganti semua'
untuk'\''
dan bungkus semuanya di dalam'...'
.Yang masih mengasumsikan bahwa string yang dikutip tidak digunakan dalam tanda kutip mundur, dan Anda masih memerlukan
--
,-P
,&&
,CDPATH=
...sumber
Solusi sederhana: Jangan panggil shell dari program Anda. Sama sekali.
Contoh Anda di sini sepele, mengubah direktori dan membuat file harus mudah dalam bahasa pemrograman apa pun. Tetapi bahkan jika Anda perlu menjalankan perintah eksternal, biasanya tidak perlu melakukannya melalui shell.
Jadi, misalnya dalam Python, alih-alih berjalan
os.system("somecmd " + somearg)
, gunakansubprocess.run(["somecmd", somearg])
. Di C, alih-alihsystem()
, gunakanfork()
danexec()
(atau temukan perpustakaan yang melakukannya).Jika Anda perlu menggunakan shell, kutip argumen baris perintah, atau sampaikan melalui lingkungan, seperti dalam jawaban Stéphane . Selain itu, jika Anda mengkhawatirkan karakter khusus, solusi yang tepat adalah tidak mencoba memfilter (daftar hitam) karakter yang berpotensi berbahaya, tetapi hanya membuat karakter yang dikenal aman (daftar putih).
Hanya izinkan karakter yang fungsinya Anda ketahui, dengan cara itu ada sedikit risiko kehilangan sesuatu. Hasil akhirnya mungkin Anda hanya memutuskan untuk mengizinkan
[a-zA-Z0-9_]
, tetapi itu mungkin cukup untuk menyelesaikan pekerjaan. Anda mungkin juga ingin memeriksa bahwa lokal dan perangkat Anda tidak menyertakan huruf beraksen sepertiä
danö
di dalamnya. Mereka mungkin tidak dianggap spesial oleh shell mana pun, tapi sekali lagi, lebih baik memastikan apakah mereka lulus atau tidak.sumber
[a-zA-Z0-9]
tidak termasuk hal-hal sepertià
yang pengkodeannya juga bisa disalahartikan oleh beberapa shell (sepertibash
) di beberapa lokal.Dalam bahasa pemrograman, harus ada cara yang lebih baik untuk melakukan sesuatu daripada mengeksekusi perintah shell. Misalnya, mengganti
cd var
dengan yang setara dengan bahasa pemrograman Andachdir (var);
harus memastikan bahwa setiap penipuan dengan nilaivar
hanya menghasilkan kesalahan "Direktori tidak ditemukan" daripada tindakan yang tidak diinginkan dan mungkin berbahaya.Anda juga dapat menggunakan jalur absolut alih-alih mengubah direktori. Cukup gabungkan nama direktori, slash, dan nama file yang ingin Anda gunakan.
Di C, saya mungkin melakukan sesuatu seperti:
Tentunya bahasa pemrograman Anda dapat melakukan hal serupa?
sumber