it-swarm-tr.com

JavaScript değerlendirme işlevini kullanmak neden kötü bir fikir?

Eval işlevi dinamik olarak kod üretmek için güçlü ve kolay bir yoldur, öyleyse uyarılar nelerdir?

503
Brian Singh
  1. Yanlış kullanım eval enjeksiyon saldırıları için kodunuzu açar

  2. Hata ayıklama daha zor olabilir (satır numarası yok, vb.)

  3. eval'd kodu daha yavaş yürütülür (eval'd kodunu derleme/önbellekleme olanağı yoktur)

Düzenleme: @Jeff Walden yorumlarda da belirtildiği gibi, # 3 bugün 2008'de olduğundan daha az doğrudur. Ancak, derlenmiş komut dosyalarının önbelleğe alınması gerçekleşebilir, ancak bu yalnızca hiçbir değişiklik yapmadan tekrarlanan komut dosyaları ile sınırlı olacaktır. Daha muhtemel bir senaryo, her seferinde küçük bir değişiklik geçirmiş olan komut dosyalarını değerlendiriyor olmanız ve önbelleğe alınamamasıdır. SOME değerlendirmesinin kodunun daha yavaş yürütüldüğünü varsayalım.

369
Prestaul

eval her zaman kötü değildir. Tamamen uygun olduğu zamanlar var.

Bununla birlikte, eval şu ​​anda ve tarihsel olarak, ne yaptıklarını bilmeyen insanlar tarafından aşırı kullanılmaktadır. Bu, ne yazık ki JavaScript öğreticileri yazan kişileri de içerir ve bazı durumlarda bunun gerçekten de güvenlik sonuçları olabilir - veya daha sıklıkla basit hatalar olabilir. Yani eval üzerine bir soru işareti atmak için ne kadar çok yapabilirsek, o kadar iyi. Eval'ü ne zaman kullanırsanız, ne yaptığınızı kontrol etmek için aklınızı kontrol etmeniz gerekir, çünkü şansınızı daha iyi, daha güvenli ve daha temiz bir şekilde yapıyor olabilirsiniz.

Çok tipik bir örnek vermek gerekirse, 'patates' değişkeninde kayıtlı bir kimliğe sahip bir öğenin rengini ayarlamak için:

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

Yukarıdaki kod türünün yazarları, JavaScript nesnelerinin nasıl çalıştığının temelleri hakkında bir ipucuna sahipse, değerlendirme ihtiyacını ortadan kaldıran değişmez nokta adları yerine köşeli parantezlerin kullanılabileceğini fark etmişlerdi:

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

... okuması çok daha kolay, hem de daha az potansiyel buggy.

(Ama sonra, ne/gerçekten/ne yaptığını bilen biri şöyle derdi:

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

bu, belge elemanından doğrudan DOM öğelerine erişme tehlikeli eski numarasından daha güvenilirdir.)

343
bobince

Bir dizgeden herhangi bir JavaScript fonksiyonunu çalıştırabileceğine inanıyorum. Kullanımı, kişilerin haydut kodu uygulamaya eklemesini kolaylaştırır.

36
kemiller2002

İki nokta akla geliyor:

  1. Güvenlik (ancak değerlendirilecek diziyi kendiniz oluşturduğunuz sürece, bu bir sorun olmayabilir)

  2. Performans: yürütülecek kod bilinmeyene kadar optimize edilemez. (javascript ve performans hakkında, kesinlikle Steve Yegge'nin sunum )

26
xtofl

Kullanıcı girdisini eval () öğesine iletmek bir güvenlik riskidir, ancak eval () uygulamasının her başlatılması JavaScript yorumlayıcısının yeni bir örneğini oluşturur. Bu bir kaynak domuzu olabilir.

20
Andrew Hedges

Genel olarak sadece eval kullanıcı girdisini geçiyorsanız sorun olur.

17
Mark Biek

Temel olarak, bakımı ve hata ayıklaması çok daha zor. goto gibi. Bunu kullanabilirsiniz, ancak sorun bulmayı zorlaştırır ve daha sonra değişiklik yapması gereken insanlar üzerinde zorlaşır.

15
Brian

Akılda tutulması gereken bir şey, başka bir şekilde kısıtlanmış bir ortamda kod yürütmek için eval () işlevini sık sık kullanabilmenizdir - belirli JavaScript işlevlerini engelleyen sosyal ağ siteleri bazen bunları bir değerlendirme bloğunda parçalayarak kandırılabilir -

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

Bu yüzden, aksi takdirde izin verilmeyebilecek bazı JavaScript kodları çalıştırmayı düşünüyorsanız ( Myspace , Sana bakıyorum ...) o zaman eval () yararlı bir numara olabilir.

Bununla birlikte, yukarıda belirtilen tüm nedenlerden dolayı, kontrolü tamamen kontrol edebileceğiniz kendi kodunuz için kullanmamalısınız - bu sadece gerekli değildir ve 'zorlu JavaScript kesmeleri' rafına bırakılmış daha iyi durumda değildir.

13
matt lohkamp

Eval () 'a dinamik bir içeriğe (cgi veya giriş yoluyla) izin vermediğiniz sürece, sayfanızdaki diğer tüm JavaScript'ler kadar güvenli ve sağlamdır.

11
Thevs

Cevapların geri kalanıyla birlikte, eval ifadelerinin en aza indirgenebileceğini düşünmüyorum.

7
Paul Mendoza

Olası bir güvenlik riskidir, farklı bir yürütme alanına sahiptir ve kodun yürütülmesi için tamamen yeni bir komut dosyası oluşturma ortamı yarattığı için oldukça yetersizdir. Daha fazla bilgi için buraya bakınız: eval .

Yine de oldukça kullanışlıdır ve ılımlılıkla kullanılan birçok işlevsellik katabilir.

6
Tom

Bu tartışmanın eski olduğunu biliyorum ama gerçekten this Google’ın yaklaşımını seviyorum ve bu hissi başkalarıyla paylaşmak istedim;)

Başka bir şey daha iyi olsun daha fazla anlamaya çalışın ve nihayet sadece bir şey söylediği için bir şeyin iyi ya da kötü olduğuna inanmıyorsunuz :) Bu çok ilham verici bir durum video ki kendi başıma daha fazla düşünmeme yardım etti :) İYİ UYGULAMALAR iyidir, ama onları dikkatsizce kullanmayın :)

5
op1ekun

Değerlendirilmekte olan kodun güvenilir bir kaynaktan (genellikle kendi uygulamanız) geldiğinden% 100 emin değilseniz, sisteminizi siteler arası komut dosyası çalıştırma saldırısına maruz bırakmanın kesin bir yoludur.

5
John Topley

Hangi bağlamda kullandığınızı bilmeniz şart değildir.

Uygulamanız, XMLHttpRequest 'den geri dönen bazı JSON’dan bir nesne oluşturmak için güvenilir sunucu tarafı kodunuz tarafından yaratılmış bir nesne oluşturmak için eval() kullanıyorsa, bu büyük olasılıkla bir sorun değildir.

Güvenilmeyen istemci tarafı JavaScript kodu zaten bu kadarını yapamaz. Çalıştığın şey varsa, eval() on, makul bir kaynaktan geldi.

5
MarkR

Güvenlik konusundaki güven düzeyinizi büyük ölçüde azaltır.

4
David Plumpton

Kullanıcının bazı mantıksal işlevler girmesini ve VE OR için değerlendirmesini istiyorsanız, JavaScript eval işlevi mükemmeldir. İki string ve eval(uate) string1 === string2, vb. Kabul edebilirim.

4
Ian

Eval () 'nun kodunuzdaki kullanımını tespit ederseniz, "eval () kötüdür" mantrasını unutmayın.

Bu işlev rasgele bir dize alır ve JavaScript kodu olarak çalıştırır. Söz konusu kod önceden bilindiğinde (çalışma zamanında belirlenmez), eval () kullanmak için hiçbir neden yoktur. Kod çalışma zamanında dinamik olarak oluşturulmuşsa, hedefi değerlendirmeden değerlendirmeden () elde etmenin daha iyi bir yolu vardır. Örneğin, dinamik özelliklere erişmek için köşeli parantez notasyonu kullanmak daha iyi ve basittir:

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

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

eval() işlevinin kullanılmasının da güvenlikle ilgili etkileri vardır, çünkü değiştirilmiş olan kodu (örneğin ağdan gelen) yürütüyor olabilirsiniz. Bu, bir Ajax isteğinden gelen bir JSON yanıtıyla uğraşırken sık karşılaşılan bir kayma önleyicidir. Bu gibi durumlarda, güvenli ve geçerli olduğundan emin olmak için JSON yanıtını ayrıştırmak için tarayıcıların yerleşik yöntemlerini kullanmak daha iyidir. JSON.parse() dosyasını doğal olarak desteklemeyen tarayıcılar için JSON.org sitesinden bir kütüphane kullanabilirsiniz.

Ayrıca, dizeleri setInterval(), setTimeout() ve Function() yapıcısına geçirmenin, çoğunlukla eval() işlevini kullanmaya benzer olduğunu ve bundan kaçınılması gerektiğini hatırlamak da önemlidir.

Perdenin arkasında, JavaScript'in hala programlama kodu olarak ilettiğiniz dizeyi değerlendirmesi ve yürütmesi gerekir:

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

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

Yeni Function () yapıcısını kullanmak eval () 'e benzer ve dikkatle yaklaşılmalıdır. Güçlü bir yapı olabilir, ancak sıklıkla yanlış kullanılır. eval() işlevini kesinlikle kullanmanız gerekiyorsa, bunun yerine yeni Function () işlevini kullanabilirsiniz.

Yeni bir İşlev () içinde değerlendirilen kod yerel bir işlev kapsamında çalışacağından, küçük bir potansiyel fayda vardır, bu nedenle değerlendirilmekte olan kodda var ile tanımlanan değişkenler otomatik olarak küresel hale gelmez.

Otomatik globals'ı önlemenin bir başka yolu, eval() çağrısını acil bir işleve sarmaktır.

3
12345678

Kullanıcı tarafından gönderilen kodu yürütüyorsanız, olası güvenlik sorunlarının yanı sıra, çoğu zaman, her yürütüldüğünde kodun yeniden ayrıştırılmasını gerektirmeyen daha iyi bir yol vardır. Anonim işlevler veya nesne özellikleri, değerlendirmenin çoğu kullanımını değiştirebilir ve çok daha güvenli ve daha hızlıdır.

2
Matthew Crumley

Yeni nesil tarayıcılar bir JavaScript derleyicisinin lezzetiyle birlikte çıktığından, bu bir sorun haline gelebilir. Eval ile yürütülen kod, JavaScript'inizin yanı sıra bu yeni tarayıcılara karşı performans göstermeyebilir. Birileri biraz profil yapmalı.

2
Brian

eval () çok güçlüdür ve bir JS ifadesini yürütmek veya bir ifadeyi değerlendirmek için kullanılabilir. Ancak soru eval () kullanımıyla ilgili değil, ancak eval () ile çalıştırdığınız dizenin kötü niyetli bir taraftan nasıl etkilendiğini açıklayalım. Sonunda kötü amaçlı kod çalıştırıyor olacaksınız. Güçle birlikte büyük sorumluluk geliyor. Yani akıllıca kullanın, kullanıyorsunuz. Bu eval () işleviyle çok ilgili değil, ancak bu makale oldukça iyi bilgiler içeriyor: http://blogs.popart.com/2009/07/javascript-injection-attacks/ Arıyorsanız eval () temelleri için buraya bakınız: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval

2
Phi

Bu, değerlendirmeden bahseden ve bunun kötülük olmadığı konusundaki iyi makalelerden biri: http://www.nczonline.net/blog/2013/06/25/eval-isnt-evil-just-misunderstood/

Her yere tükenip eval () kullanmaya başlamanız gerektiğini söylemiyorum. Aslında, eval () uygulamasının çalıştırılması için çok az iyi kullanım örneği vardır. Kesinlikle kod açıklığı, hata ayıklama ve kesinlikle göz ardı edilmemesi gereken performans konusunda endişeler var. Ancak eval () 'ın mantıklı olduğu bir vakanız olduğunda kullanmaktan korkmamalısınız. İlk önce kullanmaya çalışmayın, ancak eval () uygun şekilde kullanıldığında, kodunuzun daha kırılgan veya daha az güvenli olduğunu düşünmenize kimsenin sizi korkutmasına izin vermeyin.

2
Amr Elgarhy

Her zaman kötü bir fikir değil. Örneğin, kod oluşturma. Geçenlerde Hyperbars adında ve virtual-dom ve gidon) arasındaki boşluğu dolduracak bir kütüphane yazdım. Bunu bir gidon şablonunu ayrıştırıp sonradan sanal-dom tarafından kullanılan hyperscript 'e dönüştürerek yapar. Hiper metin ilk önce bir dize olarak üretilir ve onu döndürmeden önce çalıştırılabilir koda dönüştürmek için eval(). Bu özel durumda eval() adresini kötülüğün tam tersi olarak buldum.

Temel olarak

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

Buna

(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({}))

eval() öğesinin performansı böyle bir durumda bir sorun değildir, çünkü oluşturulan dizgeyi yalnızca bir kez yorumlamanız ve çalıştırılabilir çıktıyı birçok kez yeniden kullanmanız gerekir.

Merak ediyorsanız kod üretiminin nasıl yapıldığını görebilirsiniz burada .

1
Wikened

Daha önce söylenen hiçbir şeyi çürütmeye çalışmayacağım, ancak ((bildiğim kadarıyla) başka bir şekilde yapılamayacak olan eval () kullanımını bu şekilde sunacağım. Muhtemelen bunu kodlamanın başka yolları ve muhtemelen en iyi duruma getirme yolları vardır, ancak bu, gerçekten başka alternatifleri olmayan bir değerlendirme kullanımını göstermek için açıklık uğruna uzun süredir ve hiçbir çan ve ıslık olmadan yapılır. Yani: dinamik (veya daha doğru) programsal olarak yaratılmış nesne isimleri (değerlerin aksine).

//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: Bu arada, size nesne adlarını kullanıcı girişine dayandırmanızı (daha önce belirtilen tüm güvenlik nedenlerinden ötürü) önermem. Yine de bunu yapmak isteyeceğiniz herhangi bir iyi neden düşünemiyorum. Yine de, bunun iyi bir fikir olmayacağını işaret edeceğimi düşündüm :)

1
Carnix

Tarayıcılarda çalıştırılan javascript'te eval() işlevini kullanırsanız bunun gerçekten önemli olmadığını söyleyeceğim. * (İhtar)

Tüm modern tarayıcılarda, herhangi bir şekilde javascript keyfi çalıştırabileceğiniz bir geliştirici konsolu vardır ve herhangi bir yarı akıllı geliştirici JS kaynağınıza bakabilir ve istediklerini yapmak için ihtiyaç duydukları bitleri geliştirme konsoluna koyabilir.

* Sunucu uç noktalarınız, kullanıcı tarafından sağlanan değerlerin doğru doğrulanması ve sanitasyonuna sahip olduğu sürece, müşteri tarafında javascript'te neyin ayrıştırıldığı ve değerlendirildiği önemli olmamalıdır.

Bununla birlikte, eval() işlevini PHP içinde kullanmanın uygun olup olmadığını sormanız gerekiyorsa, cevabınız NO, eğer beyaz liste olabilir eval ifadenize geçti.

1
Adam Copley

JavaScript Engine, derleme aşamasında gerçekleştirdiği çeşitli performans optimizasyonlarına sahiptir. Bunlardan bazıları, kodu yazarken özelikle statik olarak analiz edebilmek ve tüm değişken ve fonksiyon bildirimlerinin nerede olduğunu önceden belirlemek, böylece yürütme sırasında tanımlayıcıları çözmek için daha az çaba harcayacak şekilde kaynatılır.

Ancak, Motor kodda bir değerlendirme (..) bulursa, temel olarak tanımlayıcı konumun tüm farkındalığının geçersiz olabileceğini varsaymak zorundadır, çünkü lexing zamanında tam olarak hangi kodu değerlendirmek için geçireceğiniz kodu bilmeyebilir (..) Sözlüksel kapsamı veya iletilecek nesnenin içeriğini değiştirmek için danışılacak yeni bir sözcüksel kapsam oluşturmak için.

Başka bir deyişle, karamsar anlamda, eğer değerlendirmenin (..) mevcut olması halinde yapacağı optimizasyonların çoğu anlamsızdır, bu yüzden sadece optimizasyonları hiç yapmaz.

Bu hepsini açıklar.

Referans :

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

Garbage collection

Tarayıcıların çöp toplama işlemi, değerlendirilen kodun bellekten kaldırılıp kaldırılamayacağı konusunda hiçbir fikre sahip olmadığı için sayfa yeniden yüklenene kadar saklı tutar. Kullanıcılarınız kısa bir süre içinde yalnızca sayfanızdaysa çok da kötü değil, ancak webapp için bir sorun olabilir.

İşte soruna demo için bir komut dosyası

https://jsfiddle.net/CynderRnAsh/qux1osnw/

document.getElementById("evalLeak").onclick = (e) => {
  for(let x = 0; x < 100; x++) {
    eval(x.toString());
  }
};

Yukarıdaki kod kadar basit bir şey, uygulama ölünceye kadar küçük bir miktar belleğin depolanmasına neden olur. Bu, değerlendirilen komut dosyası dev bir işlev olduğunda ve aralıklarla çağrıldığında daha kötüdür.

0
J D