Sebagian besar bahasa modern (yang entah bagaimana ditafsirkan) memiliki semacam fungsi eval . Fungsi semacam itu mengeksekusi kode bahasa yang arbitrer, sebagian besar waktu berlalu sebagai argumen utama sebagai string (bahasa yang berbeda dapat menambahkan lebih banyak fitur ke fungsi eval).
Saya memahami pengguna tidak boleh diizinkan untuk menjalankan fungsi ini ( sunting yaitu mengambil input arbitrase langsung atau tidak langsung dari pengguna arbitrer untuk diteruskan eval
), terutama dengan perangkat lunak sisi server, karena mereka dapat memaksa proses untuk mengeksekusi kode berbahaya. Dengan cara itu, tutorial dan komunitas memberi tahu kami untuk tidak menggunakan eval. Namun, ada beberapa kali eval berguna dan digunakan:
- Aturan akses khusus ke elemen perangkat lunak (IIRC OpenERP memiliki objek
ir.rule
yang dapat menggunakan kode python dinamis). - Perhitungan dan / atau kriteria khusus (OpenERP memiliki bidang seperti itu untuk memungkinkan perhitungan kode khusus).
- Parser laporan OpenERP (ya saya tahu saya membuat Anda takut dengan hal-hal OpenERP ... tapi itu adalah contoh utama yang saya miliki).
- Coding efek mantra di beberapa game RPG.
Jadi mereka memiliki penggunaan yang baik, selama mereka digunakan dengan benar. Keuntungan utama adalah bahwa fitur memungkinkan admin untuk menulis kode khusus tanpa harus membuat lebih banyak file dan memasukkannya (meskipun sebagian besar kerangka kerja menggunakan fitur eval juga memiliki cara untuk menentukan file, modul, paket, ... untuk membaca dari).
Namun, eval adalah kejahatan dalam budaya populer. Hal-hal seperti membobol sistem Anda datang ke pikiran.
Namun, ada fungsi lain yang bisa berbahaya jika entah bagaimana diakses oleh pengguna: memutuskan tautan, membaca, menulis (semantik file), alokasi memori dan aritmatika pointer, akses model database (bahkan jika tidak mempertimbangkan kasus SQL-injeksi).
Jadi, pada dasarnya, sebagian besar waktu ketika kode apa pun tidak ditulis dengan benar atau tidak ditonton dengan benar (sumber daya, pengguna, lingkungan, ...), kode tersebut jahat dan bahkan dapat mengakibatkan dampak ekonomi.
Tapi ada sesuatu yang spesial dengan eval
fungsi (terlepas dari bahasa)
Pertanyaan : Apakah ada fakta historis untuk rasa takut ini menjadi bagian dari budaya populer, alih-alih memberikan perhatian yang sama pada fitur-fitur berbahaya lainnya?
sumber
eval
, ia memiliki fungsi internal yang disebutsafe_eval
sedang mempersiapkan lingkungan untuk mencegah kode melakukan hal-hal berbahaya. Bug telah ditemukan, karena Python adalah bahasa yang cukup fleksibel, dan karenanya sulit dikendalikan.Jawaban:
Suatu
eval
fungsi dengan sendirinya bukanlah kejahatan, dan ada hal halus yang menurut saya tidak Anda buat:Mengizinkan program untuk mengeksekusi input pengguna sewenang-wenang adalah buruk
Saya telah menulis kode yang menggunakan
eval
jenis fungsi dan aman: program dan parameternya adalah hard-coded. Terkadang, tidak ada fitur bahasa atau pustaka untuk melakukan apa yang dibutuhkan oleh program dan menjalankan perintah shell adalah jalur pendek. "Saya harus menyelesaikan pengkodean ini dalam beberapa jam, tetapi menulis Java / .NET / PHP / kode apa pun akan memakan waktu dua hari. Atau saya bisaeval
melakukannya dalam lima menit."Setelah Anda mengizinkan pengguna untuk mengeksekusi apa pun yang mereka inginkan, bahkan jika dikunci oleh hak istimewa pengguna atau di belakang layar "aman", Anda membuat vektor serangan. Setiap minggu, beberapa CMS acak, perangkat lunak blog, dll. Memiliki lubang keamanan yang ditambal di mana penyerang dapat mengeksploitasi lubang seperti ini. Anda mengandalkan seluruh tumpukan perangkat lunak untuk melindungi akses ke fungsi yang dapat digunakan
rm -rf /
atau hal lain yang menimbulkan bencana (catatan: perintah itu tidak mungkin berhasil, tetapi akan gagal setelah menyebabkan sedikit kerusakan).Ya, ada preseden historis. Karena banyak bug yang telah diperbaiki selama bertahun-tahun dalam berbagai perangkat lunak yang memungkinkan penyerang jarak jauh untuk mengeksekusi kode sewenang-wenang, ide
eval
sebagian besar tidak disukai. Bahasa dan perpustakaan modern memiliki serangkaian fungsi yang kaya yang membuateval
kurang penting, dan ini bukan kebetulan. Keduanya membuat fungsi lebih mudah digunakan dan mengurangi risiko eksploitasi.Telah banyak perhatian diberikan pada banyak fitur yang berpotensi tidak aman dalam bahasa populer. Apakah seseorang menerima lebih banyak perhatian terutama adalah masalah pendapat, tetapi
eval
fitur - fiturnya tentu memiliki masalah keamanan yang dapat dibuktikan yang mudah dipahami. Untuk satu, mereka memungkinkan menjalankan perintah sistem operasi termasuk built-in shell dan program eksternal yang standar (misalnyarm
ataudel
). Dua, digabungkan dengan eksploit lain, penyerang mungkin dapat mengunggah skrip executable atau shell mereka sendiri kemudian mengeksekusinya melalui perangkat lunak Anda, membuka pintu untuk hampir semua hal terjadi (tidak ada yang baik).Ini masalah yang sulit. Perangkat lunaknya kompleks, dan tumpukan perangkat lunak (misalnya LAMP ) adalah banyak perangkat lunak yang saling berinteraksi dengan cara yang rumit. Hati-hati bagaimana Anda menggunakan fitur bahasa seperti ini, dan jangan pernah mengizinkan pengguna untuk mengeksekusi perintah sewenang-wenang.
sumber
eval
dapat meningkatkan hak istimewa. yang tidak menjadi masalah jika mereka sudah meningkat.rm -rf /
, tidak perlu melakukan itu dengan cara yang rumit melalui IDE. Masalahnyaeval
adalah itu membuka kemampuan itu bagi banyak aktor yang seharusnya tidak memiliki kemampuan itu.Sebagian darinya hanyalah nuansa yang sulit. Mudah untuk mengatakan hal seperti tidak pernah menggunakan goto, bidang publik, interpolasi string untuk kueri sql, atau eval. Pernyataan-pernyataan ini seharusnya tidak dipahami dengan mengatakan bahwa tidak pernah ada, dalam keadaan apa pun, alasan untuk menggunakannya. Tetapi menghindari mereka sebagai aturan umum adalah ide yang bagus.
Eval sangat tidak dianjurkan karena menggabungkan beberapa masalah umum.
Pertama, rentan terhadap serangan injeksi. Ini seperti injeksi SQL dimana ketika data yang dikontrol pengguna dimasukkan ke dalam kode, mudah untuk secara tidak sengaja memungkinkan kode arbitrer untuk dimasukkan.
Kedua, pemula cenderung menggunakan eval untuk mendapatkan kode yang terstruktur dengan buruk. Seorang programmer pemula dapat menulis kode yang terlihat seperti:
Ini berfungsi, tetapi sebenarnya cara yang salah untuk menyelesaikan masalah ini. Jelas, menggunakan daftar akan jauh lebih baik.
Ketiga, eval biasanya tidak efisien. Banyak upaya dihabiskan untuk mempercepat implementasi bahasa pemrograman kami. Tetapi eval sulit untuk dipercepat dan menggunakannya biasanya akan memiliki efek yang merugikan pada kinerja Anda.
Jadi, eval bukanlah kejahatan. Kita dapat mengatakan bahwa eval itu jahat, karena well, ini cara yang mudah untuk mengatakannya. Setiap programmer pemula harus benar-benar menjauh dari eval karena apa pun yang mereka ingin lakukan, eval hampir pasti merupakan solusi yang salah. Untuk kasus penggunaan tingkat lanjut tertentu, eval masuk akal, dan Anda harus menggunakannya, tetapi jelas berhati-hatilah dengan perangkapnya.
sumber
var x = 3; print(x)
sedang disusun maka tidak perlu setiap run-time pengetahuan bahwa sumber menggunakan nama "x". Agarvar x = 3; print(eval("x"))
dapat bekerja, pemetaan itu perlu direkam. Ini adalah masalah nyata: dalam Common Lisp(let ((x 3)) (print (eval 'x)))
akan membuang pengecualian variabel tidak terikat karena variabel leksikal x tidak memiliki koneksi dengan nama setelah kode dikompilasi.Intinya adalah bahwa "eksekusi kode arbitrer" adalah teknologi-bicara untuk "mampu melakukan apa saja." Jika seseorang dapat mengeksploitasi eksekusi kode arbitrer dalam kode Anda, ini secara harfiah adalah kerentanan keamanan terburuk yang mungkin terjadi, karena itu berarti mereka dapat melakukan apa saja yang mungkin dilakukan oleh sistem Anda.
"Bug lain yang mungkin berbahaya" mungkin memiliki batasan, yang berarti bahwa mereka, menurut definisi, tidak lebih berbahaya daripada eksekusi kode arbitrer yang dieksploitasi.
sumber
eval
ada.Ada alasan praktis dan teoretis.
Alasan praktisnya adalah bahwa kita mengamatinya sering menyebabkan masalah. Jarang eval menghasilkan solusi yang baik, dan seringkali menghasilkan solusi buruk di mana Anda akan mendapatkan yang lebih baik pada akhirnya jika Anda pura-pura eval tidak ada dan mendekati masalah secara berbeda. Jadi saran yang disederhanakan adalah untuk mengabaikannya, dan jika Anda menemukan sebuah kasus di mana Anda ingin mengabaikan saran yang disederhanakan, yah, semoga Anda telah memikirkannya secara cukup untuk memahami mengapa saran yang disederhanakan tidak berlaku dan yang umum perangkap tidak akan memengaruhi Anda.
Alasan yang lebih teoretis adalah bahwa jika sulit untuk menulis kode yang baik, bahkan lebih sulit untuk menulis kode yang menulis kode yang baik. Apakah Anda menggunakan eval, atau membuat pernyataan SQL dengan menggabungkan string, atau menulis kompiler JIT, apa yang Anda coba seringkali lebih sulit dari yang Anda harapkan. Potensi injeksi kode berbahaya adalah salah satu bagian besar dari masalah, tetapi selain itu pada umumnya lebih sulit untuk mengetahui kode Anda benar jika kode Anda bahkan tidak ada sampai runtime. Jadi saran yang disederhanakan adalah untuk menjaga hal-hal lebih mudah untuk diri Anda sendiri: "gunakan query SQL parameterized", "jangan gunakan eval".
Mengambil contoh efek mantra Anda: membangun kompua atau penerjemah Lua (atau apa pun) ke dalam gim Anda adalah untuk memungkinkan perancang permainan bahasa yang lebih mudah daripada C ++ (atau apa pun) untuk menggambarkan efek mantra. Sebagian besar "masalah eval" tidak berlaku jika semua yang Anda lakukan adalah mengevaluasi kode yang telah ditulis dan diuji dan dimasukkan dalam permainan atau dalam DLC atau apa pun yang Anda miliki. Itu hanya bahasa campuran. Masalah besar menghantam Anda ketika Anda mencoba untuk menghasilkan Lua (atau C ++, atau SQL, atau perintah shell, atau apa pun) dengan cepat, dan mengacaukannya.
sumber
Tidak, tidak ada fakta sejarah yang jelas.
Kejahatan eval jelas terlihat dari awal. Fitur lainnya agak berbahaya. Orang dapat menghapus data. Orang dapat melihat data yang seharusnya tidak mereka lihat. Orang dapat menulis data yang seharusnya tidak mereka lakukan. Dan mereka hanya dapat melakukan sebagian besar dari hal-hal itu jika Anda entah bagaimana mengacaukan dan tidak memvalidasi input pengguna.
Dengan eval, mereka dapat meretas pentagon dan membuatnya tampak seperti Anda melakukannya. Mereka dapat memeriksa penekanan tombol Anda untuk mendapatkan kata sandi Anda. Dengan asumsi bahasa lengkap Turing, mereka benar-benar dapat melakukan apa pun yang mampu dilakukan komputer Anda.
Dan Anda tidak dapat memvalidasi input. Ini adalah string bentuk bebas sewenang-wenang. Satu-satunya cara untuk memvalidasinya adalah dengan membuat mesin analisis parser dan kode untuk bahasa yang dimaksud. Semoga beruntung dengan itu.
sumber
Saya pikir itu bermuara pada aspek-aspek berikut:
Kebutuhan
Yang ingin saya katakan adalah: Anda perlu membaca / menulis untuk hampir semua alat dasar. Sama untuk menyimpan skor tinggi dari game oh-begitu-mengagumkan Anda.
Tanpa baca / tulis, editor gambar Anda tidak berguna. Tanpa
eval
? Saya akan menulis plugin khusus untuk Anda!(Dijaga) Penggunaan
Banyak metode yang berpotensi berbahaya. Seperti, misalnya
read
danwrite
. Contoh umum adalah layanan web yang memungkinkan Anda membaca gambar dari direktori tertentu dengan menyebutkan namanya. Namun, 'nama' sebenarnya dapat berupa jalur (relatif) yang valid pada sistem, memungkinkan Anda membaca semua file yang dapat diakses oleh layanan web, bukan hanya gambar. Menyalahgunakan contoh sederhana ini disebut 'path traversal'. Jika aplikasi Anda memungkinkan jalur traversal, itu buruk. Aread
tanpa bertahan melawan untuk jalur traversal bisa disebut kejahatan.Namun, dalam kasus lain, string untuk
read
sepenuhnya di bawah kendali programer (mungkin hardcoded?). Dalam hal ini, hampir tidak jahat untuk digunakanread
.Mengakses
Sekarang, contoh sederhana lainnya, menggunakan
eval
.Di suatu tempat di aplikasi web Anda, Anda menginginkan beberapa konten dinamis. Anda akan mengizinkan administrator untuk memasukkan beberapa kode yang dapat dieksekusi. Melihat admin adalah pengguna tepercaya, ini secara teori bisa ok. Pastikan untuk tidak mengeksekusi kode yang dikirimkan oleh non-admin, dan Anda baik-baik saja.
(Yaitu, sampai Anda memecat admin yang bagus itu tetapi lupa untuk mencabut aksesnya. Sekarang aplikasi web Anda dibuang).
Verifikasi.
Aspek lain yang penting, saya pikir, adalah betapa mudahnya memverifikasi input pengguna.
Menggunakan input pengguna dalam panggilan baca? Pastikan (sangat) yakin bahwa input untuk panggilan baca tidak mengandung sesuatu yang berbahaya. Normalisasi jalur, dan verifikasi file yang dibuka ada di direktori media Anda. Nah, itu aman.
Input pengguna pada panggilan tulis? Sama!
Injeksi SQL? Hanya menghindarinya, atau gunakan pertanyaan parametris dan Anda aman.
Eval? Bagaimana Anda akan memverifikasi input yang digunakan untuk
eval
panggilan? Anda dapat bekerja sangat keras, tetapi sangat sulit (jika bukan tidak mungkin) untuk membuatnya bekerja dengan aman.Serangan multi-tahap
Sekarang, setiap kali Anda menggunakan input pengguna, Anda perlu mempertimbangkan manfaat menggunakannya, melawan bahaya. Lindungi penggunaannya sebanyak yang Anda bisa.
Pertimbangkan lagi
eval
hal-hal yang bisa di contoh admin. Saya bilang itu tidak apa-apa.Sekarang, pertimbangkan bahwa sebenarnya ada tempat di aplikasi web Anda di mana Anda lupa untuk melarikan diri dari konten pengguna (HTML, XSS). Itu pelanggaran yang lebih rendah daripada eval yang dapat diakses pengguna. Tetapi, dengan menggunakan konten pengguna yang tidak terhapus, pengguna dapat mengambil alih browser web dari admin, dan menambahkan
eval
gumpalan yang mampu melalui sesi admin, memungkinkan lagi akses sistem penuh.(Serangan multi-tahap yang sama dapat dilakukan dengan injeksi SQL, bukan XSS, atau beberapa file arbitrer menulis menggantikan kode yang dapat dieksekusi alih-alih menggunakan
eval
)sumber
eval("hard coded string" + user_input_which_should_be_alphanumeric + "remainder")
. Memverifikasi bahwa input adalah alfanumerik dimungkinkan. Juga, 'apakah itu berhenti' adalah ortogonal untuk 'apakah ia memodifikasi / mengakses keadaan yang tidak boleh disentuh' dan 'apakah itu metode yang seharusnya tidak dipanggil'.Agar fitur ini berfungsi sama sekali, itu berarti saya harus menyimpan lapisan refleksi di sekitar yang memungkinkan akses penuh ke keadaan internal seluruh program.
Untuk bahasa yang ditafsirkan, saya cukup menggunakan status juru bahasa, yang mudah, tetapi dalam kombinasi dengan kompiler JIT masih meningkatkan kompleksitas secara signifikan.
Tanpa
eval
, kompiler JIT sering dapat membuktikan bahwa data lokal thread tidak diakses dari kode lain, sehingga sangat dapat diterima untuk menyusun ulang akses, menghilangkan kunci dan cache data yang sering digunakan untuk waktu yang lebih lama. Ketika utas lain mengeksekusieval
pernyataan, mungkin perlu menyinkronkan kode JIT yang dikompilasi yang berjalan terhadap hal itu, jadi tiba-tiba kode yang dihasilkan JIT memerlukan mekanisme mundur yang kembali ke eksekusi yang tidak dioptimalkan dalam kerangka waktu yang masuk akal.Jenis kode ini cenderung memiliki banyak bug yang halus, sulit direproduksi, dan pada saat yang sama juga membatasi optimasi pada kompiler JIT.
Untuk bahasa yang dikompilasi, pengorbanannya bahkan lebih buruk: Kebanyakan optimasi dilarang, dan saya perlu menyimpan informasi simbol yang luas dan penerjemah, sehingga fleksibilitas tambahan umumnya tidak sepadan - seringkali lebih mudah untuk mendefinisikan antarmuka ke beberapa internal struktur, misalnya dengan memberikan scripting pandangan dan pengendali akses bersamaan ke program Model .
sumber
Saya menolak premis yang
eval
dianggap lebih jahat daripada aritmatika pointer atau lebih berbahaya daripada memori langsung dan akses sistem file. Saya tidak tahu ada pengembang masuk akal yang akan percaya itu. Selain itu, bahasa yang mendukung aritmatika pointer / akses memori langsung biasanya tidak mendukungeval
dan sebaliknya, jadi saya perhatikan seberapa sering perbandingan semacam itu akan relevan.Tetapi
eval
mungkin kerentanan yang lebih terkenal , karena alasan sederhana bahwa itu didukung oleh JavaScript. JavaScript adalah bahasa berpasir tanpa memori langsung atau akses sistem file, jadi ia tidak memiliki kerentanan ini selain dari kelemahan dalam implementasi bahasa itu sendiri.Eval
Oleh karena itu salah satu fitur bahasa yang paling berbahaya, karena membuka kemungkinan eksekusi kode arbitrer. Saya percaya lebih banyak pengembang berkembang dalam JavaScript daripada di C / C ++, jadieval
cukup penting untuk diperhatikan daripada buffer overflows untuk sebagian besar pengembang.sumber
Tidak ada programmer serius yang menganggap Eval sebagai "Jahat". Ini hanyalah alat pemrograman, seperti yang lainnya. Ketakutan (jika ada ketakutan) dari fungsi ini tidak ada hubungannya dengan budaya populer. Ini hanyalah perintah berbahaya yang sering disalahgunakan, dan dapat menimbulkan celah keamanan yang serius, dan menurunkan kinerja. Dari pengalaman saya sendiri, saya akan mengatakan bahwa jarang menemukan masalah pemrograman yang tidak dapat diselesaikan dengan lebih aman dan efisien dengan cara lain. Programmer yang paling mungkin menggunakan eval, adalah mereka yang mungkin paling tidak memenuhi syarat untuk melakukannya dengan aman.
Karena itu, ada bahasa di mana penggunaan eval sesuai. Perl datang ke pikiran. Namun saya pribadi merasa sangat jarang dibutuhkan dalam bahasa lain yang lebih modern, yang secara asli mendukung penanganan pengecualian terstruktur.
sumber
Saya pikir Anda membahasnya dengan baik di bagian berikut dari pertanyaan Anda (penekanan saya):
Bagi 95% yang mungkin menggunakannya dengan benar, semuanya baik dan bagus; tetapi akan selalu ada orang yang tidak menggunakannya dengan benar. Beberapa dari mereka akan kekurangan pengalaman dan kurangnya kemampuan, sisanya akan berbahaya.
Akan selalu ada orang yang ingin mendorong batas-batas dan menemukan celah keamanan - beberapa untuk kebaikan, beberapa untuk buruk.
Adapun aspek fakta historisnya,
eval
fungsi ketik pada dasarnya memungkinkan eksekusi kode sewenang-wenang yang sebelumnya telah dieksploitasi di CMS web populer, Joomla! . Dengan Joomla! menyalakan lebih dari 2,5 juta situs di seluruh dunia , itu banyak potensi kerusakan tidak hanya bagi pengunjung ke situs-situs tersebut, tetapi juga berpotensi pada infrastruktur tempat hostingnya dan juga reputasi situs / perusahaan yang telah dieksploitasi.Joomla! Contohnya mungkin sederhana, tapi itu sudah dicatat.
sumber
Ada beberapa alasan bagus untuk mencegah penggunaan
eval
(meskipun beberapa khusus untuk bahasa tertentu).eval
sering mengejutkan (yaitu, Anda pikireval(something here)
harus melakukan satu hal, tetapi melakukan hal lain, mungkin memicu pengecualian)Secara pribadi, saya tidak akan mengatakan bahwa itu jahat, tetapi saya akan selalu menentang penggunaan
eval
dalam tinjauan kode, dengan kata-kata di sepanjang baris "apakah Anda mempertimbangkan beberapa kode di sini ?" (jika saya punya waktu untuk membuat setidaknya pengganti sementara), atau "apakah Anda yakin eval benar-benar solusi terbaik di sini?" (jika saya tidak).sumber
Dalam Masyarakat Pikiran Minsky , Bab 6.4, katanya
Ketika satu program (B) menulis program lain (A) berfungsi sebagai program-meta. Subjek B adalah program A.
Ada program C. Itulah yang ada di kepala Anda yang menulis program B.
Bahayanya adalah mungkin ada seseorang (C ') dengan niat jahat, yang dapat mengganggu proses ini, sehingga Anda mendapatkan hal-hal seperti injeksi SQL.
Tantangannya adalah membuat perangkat lunak lebih pintar tanpa membuatnya lebih berbahaya.
sumber
Anda memiliki banyak jawaban bagus di sini dan alasan utamanya jelas bahwa eksekusi kode arbitrer adalah mmmkay buruk, tetapi saya akan menambahkan satu faktor lain yang hanya disentuh orang lain di tepi:
Hal ini benar-benar sulit untuk kode permasalahan yang sedang dievaluasi dari string teks. Alat debugging normal Anda cukup banyak langsung keluar dari jendela dan Anda direduksi menjadi tracing atau gema sekolah yang sangat tua. Jelas itu tidak terlalu penting jika Anda memiliki sebuah fragmen dalam satu-liner yang Anda inginkan
eval
tetapi sebagai programmer yang berpengalaman Anda mungkin dapat menemukan solusi yang lebih baik untuk itu, sedangkan generasi kode skala yang lebih besar mungkin ada di suatu tempat di mana fungsi evaluasi menjadi sekutu yang berpotensi berguna.sumber