it-swarm-id.com

Mengapa menggunakan fungsi JavaScript JavaScript ide yang buruk?

Fungsi eval adalah cara yang kuat dan mudah untuk menghasilkan kode secara dinamis, jadi apa peringatannya?

503
Brian Singh
  1. Penggunaan yang tidak benar dari eval membuka kode Anda untuk serangan injeksi

  2. Debugging dapat lebih menantang (tidak ada nomor baris, dll.)

  3. kode eval'd mengeksekusi lebih lambat (tidak ada kesempatan untuk mengkompilasi/cache kode eval'd)

Sunting: Seperti yang ditunjukkan oleh @Jeff Walden dalam komentar, # 3 kurang benar hari ini dari pada 2008. Namun, sementara beberapa caching skrip yang dikompilasi dapat terjadi, ini hanya akan terbatas pada skrip yang dievaluasi berulang tanpa modifikasi. Skenario yang lebih mungkin adalah Anda mengevaluasi skrip yang telah mengalami sedikit modifikasi setiap kali dan karenanya tidak dapat di-cache. Anggap saja beberapa kode dijalankan lebih lambat.

369
Prestaul

eval tidak selalu jahat. Ada saat-saat di mana itu sangat tepat.

Namun, eval saat ini dan secara historis terlalu banyak digunakan oleh orang-orang yang tidak tahu apa yang mereka lakukan. Itu termasuk orang yang menulis tutorial JavaScript, sayangnya, dan dalam beberapa kasus ini memang dapat memiliki konsekuensi keamanan - atau, lebih sering, bug sederhana. Jadi semakin banyak yang bisa kita lakukan untuk melemparkan tanda tanya di atas eval, semakin baik. Setiap kali Anda menggunakan eval, Anda perlu melakukan kewarasan-memeriksa apa yang Anda lakukan, karena kemungkinan besar Anda bisa melakukannya dengan cara yang lebih baik, lebih aman, lebih bersih.

Untuk memberikan contoh yang terlalu umum, untuk mengatur warna elemen dengan id yang disimpan dalam variabel 'kentang':

eval('document.' + potato + '.style.color = "red"');

Jika penulis dari jenis kode di atas memiliki petunjuk tentang dasar-dasar cara kerja objek JavaScript, mereka akan menyadari bahwa tanda kurung siku dapat digunakan alih-alih nama-huruf literal, meniadakan perlunya eval:

document[potato].style.color = 'red';

... yang jauh lebih mudah dibaca serta kurang berpotensi buggy.

(Tapi kemudian, seseorang yang benar-benar tahu apa yang mereka lakukan akan berkata:

document.getElementById(potato).style.color = 'red';

yang lebih dapat diandalkan daripada trik lama cerdik mengakses elemen DOM langsung dari objek dokumen.)

343
bobince

Saya percaya itu karena dapat menjalankan fungsi JavaScript apa pun dari string. Menggunakannya memudahkan orang untuk menyuntikkan kode jahat ke dalam aplikasi.

36
kemiller2002

Dua poin muncul dalam pikiran:

  1. Keamanan (tetapi selama Anda menghasilkan string untuk dievaluasi sendiri, ini mungkin bukan masalah)

  2. Kinerja: sampai kode yang dieksekusi tidak diketahui, tidak dapat dioptimalkan. (tentang javascript dan kinerja, tentu saja presentasi Steve Yegge )

26
xtofl

Melewati input pengguna ke eval () adalah risiko keamanan, tetapi juga setiap permintaan eval () menciptakan instance baru dari penerjemah JavaScript. Ini bisa menjadi sumber daya babi.

20
Andrew Hedges

Ini umumnya hanya masalah jika Anda memberikan input pengguna.

17
Mark Biek

Terutama, jauh lebih sulit untuk mempertahankan dan men-debug. Ini seperti goto. Anda dapat menggunakannya, tetapi itu membuat lebih sulit untuk menemukan masalah dan lebih sulit pada orang-orang yang mungkin perlu melakukan perubahan nanti.

15
Brian

Satu hal yang perlu diingat adalah bahwa Anda sering dapat menggunakan eval () untuk mengeksekusi kode di lingkungan yang dibatasi - situs jejaring sosial yang memblokir fungsi JavaScript tertentu terkadang dapat dibodohi dengan memecahnya dalam blok eval -

eval('al' + 'er' + 't(\'' + 'hi there!' + '\')');

Jadi jika Anda ingin menjalankan beberapa kode JavaScript yang mungkin tidak diizinkan ( Myspace , saya sedang melihat Anda ...) maka eval () dapat menjadi trik yang berguna.

Namun, untuk semua alasan yang disebutkan di atas, Anda tidak boleh menggunakannya untuk kode Anda sendiri, di mana Anda memiliki kontrol penuh - itu tidak perlu, dan lebih baik diturunkan ke rak 'peretasan JavaScript yang rumit'.

13
matt lohkamp

Kecuali Anda membiarkan eval () konten dinamis (melalui cgi atau input), itu sama aman dan solidnya dengan semua JavaScript lainnya di halaman Anda.

11
Thevs

Seiring dengan sisa jawaban, saya tidak berpikir pernyataan eval dapat memiliki minimalisasi lanjutan.

7
Paul Mendoza

Ini adalah risiko keamanan yang mungkin terjadi, ia memiliki ruang lingkup eksekusi yang berbeda, dan cukup tidak efisien, karena menciptakan lingkungan scripting yang sama sekali baru untuk pelaksanaan kode. Lihat di sini untuk info lebih lanjut: eval .

Ini cukup berguna, dan digunakan dengan moderasi dapat menambah banyak fungsionalitas yang baik.

6
Tom

Saya tahu diskusi ini sudah lama, tapi saya sangat suka ini pendekatan oleh Google dan ingin berbagi perasaan itu dengan orang lain;)

Hal lain adalah bahwa semakin baik Anda mendapatkan semakin Anda mencoba untuk memahami dan akhirnya Anda hanya tidak percaya bahwa ada sesuatu yang baik atau buruk hanya karena seseorang berkata begitu :) Ini adalah sangat inspirasional video yang membantu saya untuk berpikir lebih banyak sendiri :) PRAKTEK YANG BAIK baik, tetapi jangan menggunakannya tanpa berpikir :)

5
op1ekun

Kecuali Anda 100% yakin bahwa kode yang dievaluasi berasal dari sumber tepercaya (biasanya aplikasi Anda sendiri) maka itu cara yang pasti untuk mengekspos sistem Anda terhadap serangan skrip lintas situs.

5
John Topley

Itu tidak selalu buruk asalkan Anda tahu apa konteksnya Anda menggunakannya.

Jika aplikasi Anda menggunakan eval() untuk membuat objek dari beberapa JSON yang telah kembali dari XMLHttpRequest ke situs Anda sendiri, dibuat oleh kode sisi server tepercaya Anda, itu mungkin bukan masalah.

Kode JavaScript sisi klien yang tidak dapat dipercaya toh tidak bisa berbuat banyak. Asalkan hal yang Anda jalankan eval() pada berasal dari sumber yang masuk akal, Anda baik-baik saja.

5
MarkR

Ini sangat mengurangi tingkat kepercayaan Anda tentang keamanan.

4
David Plumpton

Jika Anda ingin pengguna memasukkan beberapa fungsi logis dan mengevaluasi untuk DAN OR maka fungsi JavaScript eval sempurna. Saya dapat menerima dua string dan eval(uate) string1 === string2, dll.

4
Ian

Jika Anda melihat penggunaan eval () dalam kode Anda, ingat mantra "eval () adalah jahat."

Fungsi ini mengambil string arbitrer dan menjalankannya sebagai kode JavaScript. Ketika kode yang dimaksud diketahui sebelumnya (tidak ditentukan saat runtime), tidak ada alasan untuk menggunakan eval (). Jika kode dihasilkan secara dinamis saat runtime, sering kali ada cara yang lebih baik untuk mencapai tujuan tanpa eval (). Misalnya, hanya menggunakan notasi braket persegi untuk mengakses properti dinamis lebih baik dan sederhana:

// antipattern
var property = "name";
alert(eval("obj." + property));

// preferred
var property = "name";
alert(obj[property]);

Menggunakan eval() juga memiliki implikasi keamanan, karena Anda mungkin mengeksekusi kode (misalnya berasal dari jaringan) yang telah dirusak. Ini adalah antipattern yang umum ketika berhadapan dengan respons JSON dari permintaan Ajax. Dalam kasus tersebut, lebih baik menggunakan metode bawaan browser untuk mem-parsing respons JSON untuk memastikan itu aman dan valid. Untuk browser yang tidak mendukung JSON.parse() secara native, Anda dapat menggunakan perpustakaan dari JSON.org.

Penting juga untuk diingat bahwa meneruskan string ke setInterval(), setTimeout(), dan konstruktor Function(), untuk sebagian besar, mirip dengan menggunakan eval() dan karenanya harus dihindari.

Di balik layar, JavaScript masih harus mengevaluasi dan mengeksekusi string yang Anda berikan sebagai kode pemrograman:

// antipatterns
setTimeout("myFunc()", 1000);
setTimeout("myFunc(1, 2, 3)", 1000);

// preferred
setTimeout(myFunc, 1000);
setTimeout(function () {
myFunc(1, 2, 3);
}, 1000);

Menggunakan Function () constructor baru mirip dengan eval () dan harus didekati dengan hati-hati. Ini bisa menjadi konstruksi yang kuat tetapi sering disalahgunakan. Jika Anda benar-benar harus menggunakan eval(), Anda dapat mempertimbangkan untuk menggunakan Function baru ().

Ada sedikit manfaat potensial karena kode yang dievaluasi dalam Function () baru akan berjalan dalam lingkup fungsi lokal, sehingga variabel apa pun yang didefinisikan dengan var dalam kode yang dievaluasi tidak akan menjadi global secara otomatis.

Cara lain untuk mencegah global otomatis adalah dengan membungkus panggilan eval() menjadi fungsi langsung.

3
12345678

Selain kemungkinan masalah keamanan jika Anda mengeksekusi kode yang dikirimkan pengguna, sebagian besar waktu ada cara yang lebih baik yang tidak melibatkan penguraian ulang kode setiap kali dieksekusi. Fungsi anonim atau properti objek dapat menggantikan sebagian besar penggunaan eval dan jauh lebih aman dan lebih cepat.

2
Matthew Crumley

Ini mungkin menjadi masalah karena generasi browser berikutnya hadir dengan rasa kompiler JavaScript. Kode yang dieksekusi melalui Eval mungkin tidak berkinerja sebaik JavaScript Anda melawan browser yang lebih baru ini. Seseorang harus melakukan profiling.

2
Brian

eval () sangat kuat dan dapat digunakan untuk mengeksekusi pernyataan JS atau mengevaluasi ekspresi. Tetapi pertanyaannya bukan tentang penggunaan eval () tetapi katakan saja bagaimana string yang Anda jalankan dengan eval () dipengaruhi oleh pihak jahat. Pada akhirnya Anda akan menjalankan kode jahat. Dengan kekuatan muncul tanggung jawab besar. Jadi gunakan dengan bijak Anda menggunakannya. Ini tidak terkait banyak dengan fungsi eval () tetapi artikel ini memiliki informasi yang cukup bagus: http://blogs.popart.com/2009/07/javascript-injection-attacks/ Jika Anda mencari untuk dasar-dasar eval () lihat di sini: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval

2
Phi

Ini adalah salah satu artikel bagus yang membahas eval dan bagaimana itu bukan kejahatan: http://www.nczonline.net/blog/2013/06/25/eval-isnt-evil-just-misunderstood/

Saya tidak mengatakan Anda harus kehabisan dan mulai menggunakan eval () di mana-mana. Bahkan, ada sangat sedikit kasus penggunaan yang baik untuk menjalankan eval () sama sekali. Jelas ada kekhawatiran dengan kejelasan kode, kemampuan debug, dan tentu saja kinerja yang tidak boleh diabaikan. Tetapi Anda tidak perlu takut untuk menggunakannya ketika Anda memiliki kasus di mana eval () masuk akal. Cobalah untuk tidak menggunakannya terlebih dahulu, tetapi jangan biarkan siapa pun membuat Anda takut bahwa kode Anda lebih rapuh atau kurang aman ketika eval () digunakan dengan tepat.

2
Amr Elgarhy

Itu tidak selalu merupakan ide yang buruk. Ambil contoh, pembuatan kode. Saya baru-baru ini menulis sebuah perpustakaan bernama Hiperbar yang menjembatani kesenjangan antara virtual-dom dan setang . Ini dilakukan dengan menguraikan templat templat dan mengubahnya menjadi hyperscript yang selanjutnya digunakan oleh virtual-dom. Hyperscript dibuat sebagai string terlebih dahulu dan sebelum mengembalikannya, eval() untuk mengubahnya menjadi kode yang dapat dieksekusi. Saya telah menemukan eval() dalam situasi khusus ini kebalikan dari kejahatan.

Pada dasarnya dari

<div>
    {{#each names}}
        <span>{{this}}</span>
    {{/each}}
</div>

Untuk ini

(function (state) {
    var Runtime = Hyperbars.Runtime;
    var context = state;
    return h('div', {}, [Runtime.each(context['names'], context, function (context, parent, options) {
        return [h('span', {}, [options['@index'], context])]
    })])
}.bind({}))

Kinerja eval() bukan masalah dalam situasi seperti ini karena Anda hanya perlu menafsirkan string yang dihasilkan sekali dan kemudian menggunakan kembali output yang dapat dieksekusi berkali-kali.

Anda dapat melihat bagaimana pembuatan kode tercapai jika Anda penasaran di sini .

1
Wikened

Saya tidak akan mencoba untuk menyangkal apa pun yang dikatakan sebelumnya, tetapi saya akan menawarkan penggunaan eval ini () yang (sejauh yang saya tahu) tidak dapat dilakukan dengan cara lain. Mungkin ada cara lain untuk kode ini, dan mungkin cara untuk mengoptimalkannya, tetapi ini dilakukan dengan tangan dan tanpa bel dan peluit demi kejelasan untuk menggambarkan penggunaan eval yang benar-benar tidak memiliki alternatif lain. Yaitu: nama objek yang dibuat secara dinamis (atau lebih akurat) yang dibuat secara program (sebagai lawan dari nilai).

//Place this in a common/global JS lib:
var NS = function(namespace){
    var namespaceParts = String(namespace).split(".");
    var namespaceToTest = "";
    for(var i = 0; i < namespaceParts.length; i++){
        if(i === 0){
            namespaceToTest = namespaceParts[i];
        }
        else{
            namespaceToTest = namespaceToTest + "." + namespaceParts[i];
        }

        if(eval('typeof ' + namespaceToTest) === "undefined"){
            eval(namespaceToTest + ' = {}');
        }
    }
    return eval(namespace);
}


//Then, use this in your class definition libs:
NS('Root.Namespace').Class = function(settings){
  //Class constructor code here
}
//some generic method:
Root.Namespace.Class.prototype.Method = function(args){
    //Code goes here
    //this.MyOtherMethod("foo"));  // => "foo"
    return true;
}


//Then, in your applications, use this to instantiate an instance of your class:
var anInstanceOfClass = new Root.Namespace.Class(settings);

EDIT: omong-omong, saya tidak akan menyarankan (untuk semua alasan keamanan menunjukkan sampai sekarang) bahwa Anda mendasarkan nama objek Anda pada input pengguna. Saya tidak bisa membayangkan alasan bagus Anda ingin melakukan itu. Tetap saja, kupikir aku akan menunjukkan bahwa itu bukan ide yang bagus :)

1
Carnix

Saya akan mengatakan bahwa tidak masalah jika Anda menggunakan eval() dalam javascript yang dijalankan di browser. * (Peringatan)

Semua browser modern memiliki konsol pengembang di mana Anda dapat menjalankan javascript sewenang-wenang dan pengembang semi-cerdas dapat melihat sumber JS Anda dan memasukkan bit apa pun yang mereka perlukan ke konsol dev untuk melakukan apa yang mereka inginkan.

* Selama titik akhir server Anda memiliki validasi & sanitasi yang benar dari nilai yang diberikan pengguna, tidak masalah apa yang diuraikan dan dievaluasi di javascript sisi klien Anda.

Jika Anda bertanya apakah cocok menggunakan eval() dalam PHP namun, jawabannya adalah NO, kecuali Anda daftar putih nilai apa pun yang mungkin diteruskan ke pernyataan eval Anda.

1
Adam Copley

Mesin JavaScript memiliki sejumlah optimasi kinerja yang dilakukan selama fase kompilasi. Beberapa di antaranya bermuara pada dasarnya dapat menganalisis kode secara statis seperti lexes, dan menentukan di mana semua variabel dan deklarasi fungsi berada, sehingga dibutuhkan sedikit usaha untuk menyelesaikan pengidentifikasi selama eksekusi.

Tetapi jika Mesin menemukan eval (..) dalam kode, pada dasarnya ia harus mengasumsikan bahwa semua kesadarannya tentang lokasi pengidentifikasi mungkin tidak valid, karena ia tidak dapat mengetahui pada waktu lexing persis kode apa yang dapat Anda lewati untuk eval (..) untuk mengubah lingkup leksikal, atau konten objek yang dapat Anda gunakan untuk membuat lingkup leksikal baru untuk dikonsultasikan.

Dengan kata lain, dalam pengertian pesimistis, sebagian besar optimisasi yang dibuatnya tidak ada gunanya jika eval (..) hadir, jadi sama sekali tidak melakukan optimasi sama sekali.

Ini menjelaskan semuanya.

Referensi:

https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20&%20closures/ch2.md#eval

https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20&%20closures/ch2.md#performance

1
hkasera