Eval işlevi dinamik olarak kod oluşturmak için güçlü ve kolay bir yoludur, bu yüzden uyarılar nelerdir?
Eval işlevi dinamik olarak kod oluşturmak için güçlü ve kolay bir yoludur, bu yüzden uyarılar nelerdir?
Yanıtlar:
Uygunsuz kullanımı eval enjeksiyon saldırıları için kodunuzu açılıyor
Hata ayıklama daha zor olabilir (satır numarası vb. Yok)
değerlendirilen kod daha yavaş çalışır (değerlendirilen kodu derleme / önbellekleme fırsatı yoktur)
Düzenleme: @Jeff Walden yorumlarda belirtildiği gibi, # 3 bugün 2008 yılında olduğundan daha az doğrudur. Ancak, derlenmiş komut dosyalarının bazı önbelleğe alma olsa da, bu sadece hiçbir değişiklik ile tekrar değerlendirilen komut dosyaları ile sınırlı olacaktır. Daha olası bir senaryo, her seferinde küçük değişiklikler yapılan ve bu nedenle önbelleğe alınamayan komut dosyalarını değerlendiriyor olmanızdır. Diyelim ki BAZI değerlendirilen kod daha yavaş çalışıyor.
badHackerGuy'); doMaliciousThings();
ve kullanıcı adımı alırsanız, bir komut dosyasına yapıştırabilir ve başkalarının tarayıcılarında değerlendirebilirim, o zaman makinelerinde istediğim herhangi bir javascript'i çalıştırabilirim (örneğin, yayınlarımı + 1'lemeye zorlayın, verilerini sunucumda yayınlama vb.)
debugger;
ifadeyi kaynak kodunuza ekleyerek erişebilirsiniz . Bu, programınızın bu satırda yürütülmesini durduracaktır. Sonra bundan sonra başka bir JS dosyası gibi hata ayıklama kesme noktaları ekleyebilirsiniz.
eval her zaman kötü değildir. Mükemmel uygun olduğu zamanlar vardır.
Bununla birlikte, eval şu anda ve tarihsel olarak ne yaptığını bilmeyen insanlar tarafından aşırı derecede kullanılıyor. Bu, ne yazık ki JavaScript öğreticileri yazan kişileri içerir ve bazı durumlarda bunun gerçekten güvenlik sonuçları olabilir - veya daha sıklıkla basit hatalar. Dolayısıyla, eval üzerine soru işareti atmak için ne kadar çok şey yapabilirsek, o kadar iyidir. Eval'i her kullandığınızda, ne yaptığınızı kontrol etmelisiniz, çünkü şansınızı daha iyi, daha güvenli ve daha temiz bir şekilde yapıyor olabilirsiniz.
Çok tipik bir örnek vermek için, 'patates' değişkeninde kimliği olan 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 ipucu verselerdi, gerçek nokta isimleri yerine köşeli parantezlerin kullanılabileceğini fark etmişlerdi:
document[potato].style.color = 'red';
... okunması çok daha kolay ve daha az potansiyel olan buggy.
(Ama sonra, ne yaptığını / gerçekten bilen biri şöyle der:
document.getElementById(potato).style.color = 'red';
bu da DOM öğelerine doğrudan belge nesnesinden erişmenin tehlikeli eski numarasından daha güvenilirdir.)
JSON.parse()
yerine kullanmamalısınız eval()
?
Bir dize herhangi bir JavaScript işlevini çalıştırabilirsiniz çünkü inanıyorum. Bunu kullanmak, kullanıcıların uygulamaya haydut kod eklemesini kolaylaştırır.
İki nokta akla geliyor:
Güvenlik (ancak kendiniz değerlendirilmek üzere dizeyi oluşturduğunuz sürece bu sorun olmayabilir)
Performans: yürütülecek kod bilinmiyor olana kadar optimize edilemez. (javascript ve performans hakkında kesinlikle Steve Yegge'in sunumu )
eval
ve daha sonra bu küçük kod parçası kullanıcının B tarayıcısında çalışır
Eval () öğesine kullanıcı girdisinin iletilmesi bir güvenlik riskidir, ancak eval () 'nin her çağrılması JavaScript yorumlayıcısının yeni bir örneğini oluşturur. Bu bir kaynak domuzu olabilir.
Temel olarak, bakımı ve hata ayıklaması çok daha zordur. Bir gibi goto
. Bunu kullanabilirsiniz, ancak daha sonra değişiklik yapması gerekebilecek kişilerde sorun bulmayı zorlaştırır ve zorlaştırır.
Akılda tutulması gereken bir şey, başka bir şekilde kısıtlanmış bir ortamda kod yürütmek için eval () kullanabileceğinizdir - belirli JavaScript işlevlerini engelleyen sosyal ağ siteleri bazen bir eval blokunda parçalanarak kandırılabilir -
eval('al' + 'er' + 't(\'' + 'hi there!' + '\')');
Dolayısıyla, başka türlü izin verilmeyebilecek bir JavaScript kodu çalıştırmak istiyorsanız ( Myspace , sana bakıyorum ...) o zaman eval () yararlı bir hile olabilir.
Bununla birlikte, yukarıda belirtilen tüm nedenlerden ötürü, tam kontrolünüz olan kendi kodunuz için kullanmamalısınız - sadece gerekli değildir ve 'zor JavaScript saldırıları' rafına daha iyi bir şekilde ayrılmıştır.
[]["con"+"struc"+"tor"]["con"+"struc"+"tor"]('al' + 'er' + 't(\'' + 'hi there!' + '\')')()
Dinamik bir içeriği (cgi veya giriş yoluyla) değerlendirmenize () izin vermedikçe, sayfanızdaki diğer tüm JavaScriptler kadar güvenli ve sağlamdır.
Cevapların geri kalanıyla birlikte, eval ifadelerinin ileri düzeyde minimizasyona sahip olabileceğini düşünmüyorum.
Olası bir güvenlik riskidir, farklı bir yürütme kapsamına sahiptir ve kodun yürütülmesi için tamamen yeni bir komut dosyası ortamı oluşturduğundan oldukça verimsizdir. Daha fazla bilgi için buraya bakın: eval .
Yine de oldukça kullanışlıdır ve ılımlılıkla birlikte kullanıldığında çok sayıda iyi işlevsellik katabilir.
Değerlendirilmekte olan kodun güvenilir bir kaynaktan (genellikle kendi uygulamanızdan)% 100 emin olmadığınız sürece, sisteminizi siteler arası komut dosyası saldırılarına maruz bırakmanın kesin bir yoludur.
Bu tartışma eski biliyorum ama gerçekten böyle bu Google tarafından yaklaşımı ve bu duyguyu 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 şey iyi ya da kötü olduğuna inanmıyorsunuz :) Bu çok daha ilham verici bir video . :) İYİ UYGULAMALAR iyidir, ama onları dikkatsizce kullanmayın :)
Hangi bağlamda kullandığınızı bilmeniz şart değildir.
Uygulamanız, XMLHttpRequest'ten kendi sitenize eval()
geri gelen ve güvenilen sunucu tarafı kodunuz tarafından oluşturulan bir JSON'dan bir nesne oluşturmak için kullanıyorsa , bu muhtemelen bir sorun değildir.
Güvenilmeyen istemci tarafı JavaScript kodu zaten bunu yapamaz. Yaptığınız şeyin eval()
makul bir kaynaktan gelmesi koşuluyla, sorun yok.
Güvenlik konusundaki güven düzeyinizi büyük ölçüde azaltır.
Kullanıcının bazı mantıksal işlevler girmesini ve VE VEYA için değerlendirmesini istiyorsanız, JavaScript değerlendirme işlevi mükemmeldir. İki dizeyi kabul edebilirim eval(uate) string1 === string2
, vb.
Kodunuzda eval () kullanımını tespit ederseniz, “eval () kötü” mantrasını hatırlayın.
Bu işlev isteğe bağlı bir dize alır ve JavaScript kodu olarak yürütür. Söz konusu kod önceden biliniyorsa (çalışma zamanında belirlenmez), eval () kullanmak için bir neden yoktur. Kod çalışma zamanında dinamik olarak oluşturulursa, eval () olmadan hedefe ulaşmak için genellikle daha iyi bir yol vardır. Örneğin, dinamik özelliklere erişmek için sadece köşeli parantez gösterimini kullanmak daha iyi ve daha basittir:
// antipattern
var property = "name";
alert(eval("obj." + property));
// preferred
var property = "name";
alert(obj[property]);
eval()
Ayrıca, kurcalanan kodu (örneğin ağdan geliyor) çalıştırıyor olabileceğiniz için kullanmanın güvenlik etkileri de vardır. Bu, bir Ajax isteğinden gelen JSON yanıtıyla uğraşırken yaygın bir antipatterndir. Bu 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. Desteklemeyen tarayıcılar içinJSON.parse()
Yerel olarak JSON.org adresinden bir kütüphane kullanabilirsiniz.
Bu o geçen dizeleri hatırlamak da önemlidir setInterval()
, setTimeout()
ve Function()
yapıcı kullanmaya benzer çoğunlukla için olduğunu eval()
ve bu nedenle kaçınılmalıdır.
Sahne arkasında, JavaScript'in 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 () işlevine benzer ve dikkatle yaklaşılmalıdır. Güçlü bir yapı olabilir, ancak sıklıkla yanlış kullanılır. Kesinlikle kullanmanız gerekiyorsa eval()
, bunun yerine yeni İşlev () kullanmayı düşünebilirsiniz.
Yeni Function () içinde değerlendirilen kod yerel bir işlev kapsamında çalışacağı için küçük bir potansiyel fayda vardır, bu nedenle değerlendirilmekte olan kodda var ile tanımlanan değişkenler otomatik olarak global olmayacaktır.
Otomatik globalleri önlemenin bir başka yolu da eval()
çağrıyı hemen bir işleve sarmaktır
.
Kullanıcı tarafından gönderilen kodu yürütüyorsanız olası güvenlik sorunlarının yanı sıra, çoğu zaman kodu her yürütüldüğünde yeniden ayrıştırmayı içermeyen daha iyi bir yol vardır. Anonim işlevler veya nesne özellikleri, eval'ün çoğu kullanımının yerini alabilir ve çok daha güvenli ve daha hızlıdır.
Bu, eval ve nasıl bir kötülük olmadığı hakkında konuşan iyi makalelerden biridir: http://www.nczonline.net/blog/2013/06/25/eval-isnt-evil-just-misunderstood/
Ben bitirmek ve her yerde eval () kullanmaya başlamak gerektiğini söylemiyorum. Aslında, eval () işlevini çalıştırmak için çok az iyi kullanım durumu vardır. Kod açıklığı, hata ayıklama ve kesinlikle göz ardı edilmemesi gereken performansla ilgili endişeler vardır. Ancak eval () 'in mantıklı olduğu bir vakanız olduğunda kullanmaktan korkmamalısınız. Önce kullanmamaya çalışın, ancak eval () uygun şekilde kullanıldığında kodunuzun daha kırılgan veya daha az güvenli olduğunu düşünmesine izin vermeyin.
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ı ile ilgili değildir, sadece eval () ile çalıştırdığınız dizenin kötü niyetli bir taraftan nasıl etkilendiğini söyleyelim. Sonunda kötü amaçlı kod çalıştırıyorsunuz. Güç ile büyük sorumluluk gelir. Bu yüzden akıllıca kullanın. Bu eval () işlevi ile çok ilgili değildir, ancak bu makalede oldukça iyi bilgiler vardır: http://blogs.popart.com/2009/07/javascript-injection-attacks/ eval () ile ilgili temel bilgileri arıyorsanız buraya bakın: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval
JavaScript Engine, derleme aşamasında gerçekleştirdiği bir dizi performans optimizasyonuna sahiptir. Bunlardan bazıları, kodu lex olarak temel olarak statik olarak analiz edebilmek ve tüm değişken ve işlev bildirimlerinin nerede olduğunu önceden belirlemek için kaynar, böylece yürütme sırasında tanımlayıcıları çözmek daha az çaba gerektirir.
Ancak Motor kodda bir eval (..) bulursa, esas olarak tanımlayıcı konumunun tüm farkındalığının geçersiz olabileceğini varsaymalıdır, çünkü lexing zamanında eval'e hangi kodu geçirebileceğinizi tam olarak bilemez (..) yeni bir sözlüksel kapsam oluşturmak için sözcüksel kapsamı veya geçebileceğiniz nesnenin içeriğini değiştirmek için.
Başka bir deyişle, kötümser anlamda, eval (..) mevcutsa yapacağınız optimizasyonların çoğu anlamsızdır, bu yüzden optimizasyonları hiç yapmaz.
Bu her şeyi açıklıyor.
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
Bu her zaman kötü bir fikir değildir. Örneğin, kod oluşturma. Son zamanlarda, sanal dom ve gidon arasındaki boşluğu köprüleyen Hyperbars adlı bir kütüphane yazdım . Bunu, bir gidon şablonunu ayrıştırarak ve daha sonra sanal dom tarafından kullanılan hiperscript'e dönüştürerek yapar . Hiper metin önce bir dize olarak oluşturulur ve döndürülmeden önce çalıştırılabilir koda dönüştürülür. Bu özel durumda kötülüğün tam tersini buldum .eval()
eval()
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()
Oluşturulan dizeyi yalnızca bir kez yorumlamanız ve ardından yürütülebilir çıktıyı birçok kez yeniden kullanmanız gerektiğinden, böyle bir durumda performans bir sorun değildir.
Burada merak ediyorsanız kod oluşturma işleminin nasıl gerçekleştirildiğini görebilirsiniz .
eval()
Tarayıcılarda çalıştırılan javascript'te kullanmanın gerçekten önemli olmadığını söyleyecek kadar ileri giderdim . * (İhtar)
Tüm modern tarayıcılarda yine de keyfi javascript çalıştırabileceğiniz bir geliştirici konsolu vardır ve herhangi bir yarı akıllı geliştirici JS kaynağınıza bakabilir ve istedikleri şeyi yapmak için ihtiyaç duydukları her şeyi geliştirici konsoluna koyabilir.
* Sunucu uç noktalarınız kullanıcı tarafından sağlanan değerlerin doğru doğrulanması ve dezenfeksiyonu olduğu sürece, istemci tarafı javascriptinizde neyin ayrıştırıldığı ve değerlendirildiği önemli değildir.
eval()
Ancak PHP'de kullanmanın uygun olup olmadığını sormak isterseniz , eval ifadenize iletilebilecek herhangi bir değeri beyaz listeye eklemediğiniz sürece cevap NO'dur .
Şimdiye kadar söylenen hiçbir şeyi reddetmeye çalışmayacağım, ancak eval () 'in (bildiğim kadarıyla) başka bir şekilde yapılamayacağını bu şekilde sunacağım. Muhtemelen bunu kodlamanın başka yolları ve muhtemelen onu optimize etmenin yolları vardır, ancak bu, uzun süre ve herhangi bir çan ve ıslık olmadan, başka alternatifleri olmayan bir eval kullanımını göstermek için yapılır. Yani: dinamik olarak (veya daha doğru) programla oluşturulan nesne adları (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, (şimdiye kadar işaret edilen tüm güvenlik nedenleriyle) size nesne adlarını kullanıcı girişine dayandırmanızı önermem. Yine de bunu yapmak için iyi bir neden düşünemiyorum. Yine de, bunun iyi bir fikir olmayacağına dikkat çekeceğimi düşündüm :)
namespaceToTest[namespaceParts[i]]
, burada değerlendirme gerek yok, bu yüzden if(typeof namespaceToTest[namespaceParts[i]] === 'undefined') { namespaceToTest[namespaceParts[i]] = {};
tek farkelse namespaceToTest = namespaceToTest[namespaceParts[i]];
Çöp toplama
Tarayıcıların çöp toplama işlemi, değerlendirilen kodun bellekten kaldırılıp kaldırılamayacağı konusunda bir fikre sahip olmadığından, sayfa yeniden yüklenene kadar depolanmış olarak kalır. Kullanıcılarınız kısa süre içinde sayfanızda ise çok kötü değil, ancak web uygulamaları için bir sorun olabilir.
İşte sorunu gösterecek 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 az miktarda belleğin depolanmasına neden olur. Değerlendirilen komut dosyası dev bir işlev olduğunda ve aralıkta çağrıldığında bu daha kötüdür.