JavaScript'in eval () değeri ne zaman kötü değildir?


263

Kullanıcı tarafından girilen işlevleri (elektronik tablo benzeri işlevler için) ayrıştırmak için bazı JavaScript kodları yazıyorum. Formülü ayrıştırılır olması olabilir JavaScript dönüştürmek ve çalıştırmak eval()sonucu elde etmek için, üzerinde.

Ancak, eval()kötü olduğu için kaçınabiliyorsam her zaman uzak durdum (ve doğru ya da yanlış, her zaman JavaScript'te daha kötü olduğunu düşündüm, çünkü değerlendirilecek kod kullanıcı tarafından değiştirilebilir ).

Peki, bunu kullanmak uygun olduğunda?


5
Çoğu JSON kütüphanesi, güvenlik risklerine karşı tam olarak korumak için gerçekte başlık altında eval kullanmaz.
Sean McMillan

11
@Sean - Hem JQuery hem de Prototip kullanım eval (JQuery yeni İşlev üzerinden kullanır)
plodder

5
@plodder - Bilgilerinizi nereden alıyorsunuz? jQuery 1.4'ten beri yerel JSON.parse () yöntemini kullanmıştır (1/2010'da geri dönüş)! Kendiniz görün: code.jquery.com/jquery-1.4.js
ken

3
"Tabii ki JSON ayrıştırmak için eval () kullanmak zorunda" - bu doğru değil, aksine - JSON ayrıştırmak için eval kullanmamalıdır! Douglas Crockfords'ın (JSON yaratıcısı) json.org'daki json2.js komut dosyasını kullanın !
TMS

11
@Tomas orada ironi json2.js JSON ayrıştırmak için eval kullanır
tobyodavies

Yanıtlar:


262

Sorunuzun öncülüne değinmek için bir dakikanızı ayırmak istiyorum - eval () " kötü ". İnsanların programlanmasıyla kullanılan " kötü " kelimesi , genellikle "tehlikeli" veya daha kesin olarak "basit görünümlü bir komutla çok fazla zarara neden olabilen" anlamına gelir. Peki, tehlikeli bir şeyi kullanmak ne zaman uygun olur? Tehlikenin ne olduğunu ve uygun önlemleri aldığınızda.

Bu noktaya kadar, eval () kullanımındaki tehlikelere bakalım. Muhtemelen her şey gibi birçok küçük gizli tehlike vardır, ancak iki büyük risk - eval () 'in kötü olarak kabul edilmesinin nedeni - performans ve kod enjeksiyonudur.

  • Performans - eval () yorumlayıcı / derleyiciyi çalıştırır. Kodunuz derlenmişse, bu büyük bir isabettir, çünkü çalışma süresinin ortasında muhtemelen ağır bir derleyici çağırmanız gerekir. Bununla birlikte, JavaScript hala çoğunlukla yorumlanmış bir dildir, bu da eval () çağrısının genel durumda büyük bir performans isabeti olmadığı anlamına gelir (ancak aşağıdaki özel açıklamalarıma bakın).
  • Kod yerleştirme - eval (), potansiyel olarak yükseltilmiş ayrıcalıklar altında bir kod dizesi çalıştırır. Örneğin, yönetici / kök olarak çalışan bir program asla kullanıcı girdisini değerlendirmek istemez, çünkü bu girdi potansiyel olarak "rm -rf / etc / important-file" veya daha kötü olabilir. Yine, bir tarayıcıdaki JavaScript'in bu sorunu yoktur, çünkü program yine de kullanıcının kendi hesabında çalışıyor. Sunucu tarafı JavaScript'te bu sorun olabilir.

Özel durumunuz için açık. Anladığım kadarıyla, dizeleri kendiniz üretiyorsunuz, bu yüzden "rm -rf önemli bir şey" gibi bir dizenin oluşturulmasına izin vermemeye dikkat ederseniz, kod enjeksiyon riski yoktur (ancak lütfen unutmayın, çok çok genel durumda bunu sağlamak zor ). Ayrıca, tarayıcıda çalıştırıyorsanız, kod enjeksiyonu oldukça küçük bir risktir, inanıyorum.

Performansa gelince, bunu kodlama kolaylığına karşı ağırlıklandırmanız gerekir. Formülü ayrıştırırsanız, başka bir ayrıştırıcıyı (eval () içindeki) ayrıştırmak yerine sonucu ayrıştırma sırasında da hesaplayabileceğinizi düşünüyorum. Ancak eval () kullanarak kodlamak daha kolay olabilir ve performans isabeti muhtemelen fark edilmeyecektir. Bu durumda eval (), size biraz zaman kazandırabilecek diğer herhangi bir fonksiyondan daha kötü değildir.


78
Eval

48
Kullanıcılarınızın verileriyle ilgili endişeleriniz varsa, Kod Ekleme javascript için çok ciddi bir konudur. Enjekte edilen kod, sitenizden gelmiş gibi (tarayıcıda) çalışır ve kullanıcının manuel olarak yapabileceği her türden shenanigan yapmasına izin verir. (Üçüncü taraf) kodunun size girmesine izin verirseniz, müşteriniz adına bir şeyler sipariş edebilir veya gravatarlarını veya sitenizden yapabileceklerini değiştirebilir. Çok dikkatli ol. Bilgisayar korsanlarının müşterilerinize sahip olmasına izin vermek, sunucunuzun sahibi olmalarına izin vermek kadar kötüdür.
Sean McMillan

71
Veriler sunucunuzdan ve sizin oluşturduğunuz bir şeyden geliyorsa, geliştirici oluşturdu, eval () kullanmanın bir zararı yoktur. Asıl zarar okuduğunuz her şeye inanmaktır. Eval () 'in kötü olduğunu söyleyen birçok insan görüyorsunuz ve neden bir yerde okudukları dışında bir fikirleri yok.
Vince Panuccio

42
@Sean McMillan: Sana inanmak istiyorum, ancak birisi eval()sunucunuzdan gelen javascript'i arayacak ve değiştirecekse , ilk etapta sayfanın kaynağını da değiştirebilir ve ayrıca kullanıcının bilgilerini kontrol edebilir. . . Farkı görmüyorum.
Walt W

20
Re "Kod enjeksiyon - ... Yine, bir tarayıcıda JavaScript bu sorun yok" & "Ayrıca, tarayıcıda çalıştırıyorsanız o zaman kod enjeksiyon oldukça küçük bir risk olduğuna inanıyorum." Tarayıcıda kod enjeksiyonunun bir sorun olmadığını mı düşünüyorsunuz? XSS, birkaç yıldır OWASP'in ilk 10 listesinde ilk 3 vulvada yer aldı.
Mike Samuel

72

eval()kötü değil. Ya da öyleyse, yansıma, dosya / ağ G / Ç, iş parçacığı ve IPC'nin diğer dillerde "kötü" olduğu gibi kötüdür.

Eğer, senin amaç için , eval()manuel yorumlanması daha hızlıdır veya kod daha basit veya daha net yapar ... o zaman bunu kullanmalıdır. Hiçbiri değilse, o zaman yapmamalısınız. Bu kadar basit.


5
Böyle bir amaç, elle yazmak için çok uzun veya çok tekrarlanan optimize edilmiş kod oluşturmak olabilir. LISP'de bir makro gerektirecek türden şeyler.
wberry

5
Bu öyle genel bir tavsiyedir ki, mevcut herhangi bir kod bloğuna uygulanabilir. Bu soruya gerçekten bir şey eklemiyor; özellikle, buraya gelen kimsenin özel kullanımlarının sorunlu olup olmadığını belirlemesine yardımcı olmaz.
jpmc26

2
Daha hızlı, daha basit, daha net ... Bu cevap güvenlik sonuçlarını yeterince iyi kapsamaz.
Ruud Helderman

55

Kaynağa güvendiğinde.

JSON durumunda, kontrol ettiğiniz bir web sunucusundan geldiğinden, kaynağa müdahale etmek aşağı yukarı zordur. JSON'un kendisi bir kullanıcının yüklediği hiçbir veri içermediği sürece, eval kullanmanın büyük bir dezavantajı yoktur.

Tüm diğer durumlarda, eval () için beslemeden önce kullanıcı tarafından sağlanan verilerin kurallara uyduğundan emin olmak için büyük çaba sarf ederim.


13
Bir json dizesi eval () 'da kullanılmadan önce her zaman json dilbilgisine karşı test edilmelidir. Dolayısıyla "alert ('XSS')" uygun bir değer olmadığından "{foo: alert ('XSS')}" json dizesi geçmez.
Gumbo

3
Öyleyse, HTTPS kullanın. OTOH: ortadaki adam, bahçe çeşitliliği web uygulaması için tipik bir saldırı senaryosu değil, diğer bir deyişle siteler arası komut dosyası oluşturmadır.
Tomalak

7
evalgeçerli tüm JSON dizelerini de doğru şekilde ayrıştırmaz. Örneğin JSON.parse(' "\u2028" ') === "\u2028"fakat eval(' "\u2028" ')U + 2028 JavaScript bir satır ama kadarıyla JSON söz konusu olduğunda bir satır olmadığı için bir özel durum oluşturur.
Mike Samuel

1
@Justin - protokol tehlikeye atılırsa, genellikle, ilk sayfa yükü aynı protokol üzerinden gönderilirdi ve o zaman bu bir tartışma noktası çünkü istemci zaten olabildiğince tehlikeye atılmış.
antinome

1
Güzelce @Tomalak, şu anda cevabımda bahsettim! Müthiş!
NiCk Newman

25

Gerçek millet alalım:

  1. Artık her büyük tarayıcı, herhangi bir değere sahip herhangi bir işlevi çağırmak için bilgisayar korsanınızın bolca kullanabileceği yerleşik bir konsola sahiptir - neden olsa bile bir değerlendirme ifadesi kullanmaktan rahatsız olurlar?

  2. 2000 satır JavaScript derlemesi 0.2 saniye sürerse, dört JSON satırını değerlendirirsem performans düşüşüm nedir?

Crockford'un 'eval is evil' için açıklaması bile zayıf.

eval Kötülüktür, eval işlevi JavaScript'in en çok kullanılan özelliğidir. Bunu önlemek

Crockford'un kendisinin dediği gibi "Bu tür açıklamalar irrasyonel nevroz üretme eğilimindedir. Satın alma."

Değerlendirmeyi anlamak ve ne zaman faydalı olabileceğini bilmek çok daha önemlidir. Örneğin eval, yazılımınız tarafından oluşturulan sunucu yanıtlarını değerlendirmek için mantıklı bir araçtır.

BTW: Prototype.js, eval'i doğrudan beş kez çağırır (evalJSON () ve evalResponse () dahil). jQuery, parseJSON'da (İşlev yapıcısı aracılığıyla) kullanır.


10
JQuery, eval'i yalnızca bir geri dönüş mekanizması olarak kullanarak, tarayıcının yerleşik JSON.parse işlevini (varsa çok daha hızlı ve daha güvenli) kullanır. "Eval kötüdür" ifadesi oldukça iyi bir rehberdir.
jjmontes

30
Re "Her büyük tarayıcının artık yerleşik bir konsolu var ...". Kod yerleştirme, bir kullanıcı daha sonra başka bir kullanıcının tarayıcısında çalıştırılan kodu girebildiğinde bir sorundur. Tarayıcı konsolları tek başına bir kullanıcının başka bir kullanıcının tarayıcısında kod çalıştırmasına izin vermez, bu nedenle kod enjeksiyonuna karşı korumaya değip değmeyeceğine karar verirken ilgisizdir.
Mike Samuel

28
"Artık her büyük tarayıcının yerleşik bir konsolu var ... neden bir eval ifadesi kullanmaktan rahatsız olurlar?" - İz bıraktın. Cevabı düzenlemenizi öneririm. Bir kullanıcının başka birinin tarayıcısında çalışabilecek kodu enjekte edebilmesi büyük bir sorundur. Ve gerçekten gerçek olman gereken yer burası.
akkishore

5
@akkishore, fazla ifade edilen ifadelerinizi destekleyen gerçek bir yaşam örneği bulursanız sevinirim.
Akash Kava

7
@AkashKava Fark edemediğiniz şey, yorum kutuma javascript gönderirsem ve bu javascript veritabanına yapar. Başka bir kullanıcı bu yorumu görüntülediğinde (javascript'i koyduğumda) eval, işlendiğinde bu javascript'i alır ve yorumlayıcıyı kullanarak değerlendirerek gömülü javascriptimin diğer kullanıcının tarayıcısında çalışmasına neden olur. Bunu yaparak her türlü bilgiyi canlandırabilirim. Kullanıcı adları, veritabanındaki kullanıcı kimlikleri, e-posta adresleri, vb. Bu zor bir cevap değildir, Googled XSS'iniz varsa, yaklaşık 10 saniye içinde bunun neden bir sorun olduğunu görürsünüz.
Kyle Richter

18

Ben takip etme eğiliminde Crockford tavsiyesine için eval()ve tümüyle kaçınmak. Gerektiren yollar bile gerektirmez. Örneğin, setTimeout()eval yerine bir fonksiyon geçirmenize izin verir.

setTimeout(function() {
  alert('hi');
}, 1000);

Güvenilir bir kaynak olsa bile, bunu kullanmıyorum, çünkü JSON tarafından döndürülen kod bozuk olabilir, ki bu en iyi ihtimalle sakat bir şey yapabilir, en kötü ihtimalle kötü bir şey ortaya çıkarabilir.


2
Sunucu tarafında JSON biçimlendirici hatalar kesinlikle bir sorun olduğunu düşünüyorum. Sunucudan gelen yanıt, kullanıcının gönderdiği herhangi bir metne mi bağlı? O zaman XSS'yi izlemelisin.
williams

3
Web sunucunuzun kimlik doğrulaması HTTPS aracılığıyla doğrulanmadıysa, başka bir ana bilgisayarın isteği durdurduğu ve kendi verilerini gönderdiği bir tür ortadaki adam saldırısına maruz kalabilirsiniz.
Ben Combee

11
Birisi ortadaki adam saldırısı yapabilirse, komut dosyalarınıza kolayca bir şey enjekte edebilir.
el.pescado

10
Javascript kodunuza hiç güvenmemelisiniz ... İstemci tarafında çalışan hiçbir şeye güvenmemelisiniz ... Birisi ortadaki adam saldırısı yaparsa neden json nesnelerinizle uğraşasın ki? Size ve farklı js dosyalarına farklı bir web sayfası sunabilir ...
Calmarius

5
Ben şahsen "bunu yapmanın her zaman başka yolları var" argümanından hoşlanmıyorum. Örneğin, her zaman nesne yönelimli programlamayı önlemenin de yolları olduğunu söyleyebilirsiniz. Bu harika bir seçenek olmadığı anlamına gelmez. Eval ve bunun tehlikelerini anlarsanız, doğru durumlarda kullanmak için harika bir araç olabilir.
dallin

4

İnsanların eval kullanmamalarını savunduğunu gördüm, çünkü kötülük , ama aynı insanların Function ve setTimeout'u dinamik olarak kullandıklarını gördüm, bu yüzden evalleri davlumbazların altında kullanıyorlar : D

BTW, sanal alanınız yeterince emin değilse (örneğin, kod enjeksiyonuna izin veren bir sitede çalışıyorsanız) eval, sorunlarınızın sonuncusudur. Güvenliğin temel kuralı, tüm girdilerin kötü olması, ancak JavaScript durumunda bile JavaScript'in kendisi kötü olabilir, çünkü JavaScript'te herhangi bir işlevin üzerine yazabilirsiniz ve gerçek olanı kullandığınızdan emin olamazsınız, bu nedenle, sizden önce kötü amaçlı bir kod başlarsa, JavaScript yerleşik işlevlerine güvenemezsiniz: D

Şimdi bu gönderinin epilogu:

Eğer varsa GERÇEKTEN (eval olduğu zaman% 80 lüzum DEĞİL gerekli) ve emin sen' yapıyoruz, sadece eval (veya daha iyi Fonksiyonu;) kullanmak ne konum), kapatmalar ve cepten tarih ve 80 /% 90'nını eval başka bir mantık kullanılarak değiştirilebilir, geri kalanı dinamik olarak oluşturulan kod (örneğin, bir tercüman yazıyorsanız) ve daha önce söylediğin gibi JSON'u değerlendirirken (burada Crockford güvenli değerlendirmesini kullanabilirsiniz;))


Ve Crockford'un da işaret ettiği gibi , mevcut web tarayıcıları yerleşik bir JSON.parse işlevine sahiptir .
Ruud Helderman

4

Eval, kodun ayarlanmasında kullanılan derlemeyi tamamlayıcı niteliktedir. Şablonlama ile, geliştirme hızını artıran yararlı şablon kodu üreten basitleştirilmiş bir şablon oluşturucu yazdığınız anlamına gelir.

Geliştiricilerin EVAL kullanmadığı bir çerçeve yazdım, ancak çerçevemizi kullanıyorlar ve bu çerçeve şablonlar oluşturmak için EVAL'i kullanmak zorunda.

EVAL performansı aşağıdaki yöntem kullanılarak artırılabilir; komut dosyasını yürütmek yerine bir işlev döndürmeniz gerekir.

var a = eval("3 + 5");

Şu şekilde organize edilmelidir:

var f = eval("(function(a,b) { return a + b; })");

var a = f(3,5);

Önbellekleme f kesinlikle hızı artıracaktır.

Ayrıca Chrome, bu tür işlevlerin kolayca hata ayıklamasına izin verir.

Güvenlik ile ilgili olarak, eval ya da not kullanmak hiç fark etmez,

  1. Her şeyden önce, tarayıcı tüm komut dosyasını bir sanal alanda çağırır.
  2. EVAL'de kötü olan herhangi bir kod, tarayıcının kendisinde kötüdür. Saldırgan veya DOM'da bir komut dosyası düğümünü kolayca enjekte edebilir ve herhangi bir şeyi değerlendirebilirse her şeyi yapabilir. EVAL kullanılmaması fark yaratmaz.
  3. Zararlı olan sunucu tarafı güvenliği çoğunlukla zayıftır. Kötü çerezlerin doğrulanması veya sunucudaki zayıf ACL uygulaması saldırıların çoğuna neden olur.
  4. Java'nın yerel kodunda yeni bir Java güvenlik açığı vb. Vardı. JavaScript bir sanal alanda çalışacak şekilde tasarlanmıştı ve uygulamalar ise güvenlik açıklarına ve diğer birçok şeye yol açan sertifikalar vb. İle bir sanal alanın dışında çalışacak şekilde tasarlanmıştır.
  5. Bir tarayıcıyı taklit etmek için kod yazmak zor değildir. Tek yapmanız gereken, favori kullanıcı aracısı dizenizle sunucuya bir HTTP isteği yapmaktır. Tüm test araçları tarayıcıları yine de alay eder; bir saldırgan size zarar vermek isterse, EVAL onların son çaresi. Sunucu tarafı güvenliğinizle başa çıkmanın birçok yolu var.
  6. DOM tarayıcısının dosyalara erişimi yoktur, kullanıcı adı yoktur. Aslında, eval'in erişebileceği makinede hiçbir şey yoktur.

Sunucu tarafı güvenliğiniz herhangi bir yerden herhangi birine saldırabilecek kadar sağlamsa, EVAL için endişelenmemelisiniz. Bahsettiğim gibi, EVAL olmasaydı, saldırganların tarayıcınızın EVAL özelliğinden bağımsız olarak sunucunuza saldırmak için birçok aracı vardır.

Eval sadece önceden kullanılmayan bir şeye dayalı karmaşık dize işleme yapmak için bazı şablonlar oluşturmak için iyidir. Örneğin, tercih edeceğim

"FirstName + ' ' + LastName"

Aksine

"LastName + ' ' + FirstName"

Görünen adım olarak, bir veritabanından gelebilir ve sabit kodlanmamış.


Eval - yerine işlevi kullanabilirsiniz function (first, last) { return last + ' ' + first }.
Konrad Borowski

Sütunların adları veritabanından gelir.
Akash Kava

3
Tehdidi evalçoğunlukla diğer kullanıcılardır . Diyelim ki bir ayarlar sayfanız var ve adınızın başkalarına nasıl görüneceğini ayarlamanıza izin veriyor. Diyelim ki yazarken çok net düşünmüyorsunuz, bu nedenle seçim kutunuzda seçenekler var <option value="LastName + ' ' + FirstName">Last First</option>. Geliştirme araçlarımı açıyorum value, bir seçeneğin değerini alert('PWNED!')değiştiriyorum, değiştirilen seçeneği seçiyorum ve formu gönderiyorum. Şimdi, başka bir kişi görünen adımı her gördüğünde, bu kod çalışır.
cHao

@cHao, Bahsettiğiniz kötü sunucu tarafı güvenlik örneği, sunucu asla kimsenin tarayıcısında kod olarak çalıştırılabilecek verileri kabul etmemelidir. Bir kez daha, kötü sunucu tarafı güvenlik kavramını anlayamadınız.
Akash Kava

1
İsterseniz sunucu tarafı güvenliği hakkında sızabilir, ancak tüm evalamacı yazdığınız komut dosyasının bir parçası olmayan kodu çalıştırmaktır. Bunu yapmak için güce ihtiyacınız yoksa (ve neredeyse hiç yapmazsanız), kaçınmak evaltüm sorun kategorilerini ortadan kaldırmaya yardımcı olur. Sunucu tarafı kodunuz mükemmel değilse, bu iyi bir şeydir.
cHao

4

Chrome'da hata ayıklarken (v28.0.1500.72), kapanmayı üreten iç içe bir işlevde kullanılmazsa değişkenlerin kapaklara bağlı olmadığını gördüm. Sanırım, bu JavaScript motorunun bir optimizasyonu.

AMA : eval()kapanmaya neden olan bir fonksiyonun içinde kullanıldığında, TÜM dış fonksiyon değişkenleri kullanılmasalar bile kapanmaya bağlanır. Birisi bununla bellek sızıntılarının üretilip üretilemeyeceğini test etmek için zamana sahipse, lütfen bana aşağıda bir yorum bırakın.

İşte test kodum:

(function () {
    var eval = function (arg) {
    };

    function evalTest() {
        var used = "used";
        var unused = "not used";

        (function () {
            used.toString();   // Variable "unused" is visible in debugger
            eval("1");
        })();
    }

    evalTest();
})();

(function () {
    var eval = function (arg) {
    };

    function evalTest() {
        var used = "used";
        var unused = "not used";

        (function () {
            used.toString();   // Variable "unused" is NOT visible in debugger
            var noval = eval;
            noval("1");
        })();
    }

    evalTest();
})();

(function () {
    var noval = function (arg) {
    };

    function evalTest() {
        var used = "used";
        var unused = "not used";

        (function () {
            used.toString();    // Variable "unused" is NOT visible in debugger
            noval("1");
        })();
    }

    evalTest();
})();

Burada belirtmek istediğim şey, eval () mutlaka yerel eval()işlevine başvurmak zorunda değildir . Her şey işlevin adına bağlıdır . Bu nedenle, yerel eval()adı bir takma adla (diyelim var noval = eval;ve sonra bir iç işlevde noval(expression);) çağırırken, expressionkapanışın bir parçası olması gereken, ancak aslında olmayan değişkenleri ifade ettiğinde değerlendirilmesi başarısız olabilir.



3

Sonuç olarak

Kodu oluşturduysanız veya sterilize ettiyseniz eval, asla kötülük yapmaz .

Biraz Daha Ayrıntılı

evalolan kötülük bir istemci tarafından gönderilen girişi kullanarak sunucu üzerinde çalışan eğer geliştirici tarafından oluşturulmamış veya edildi geliştirici tarafından temizlenmiş değil .

evalolan şeytan değil , istemci üzerinde çalışan eğer müşteri tarafından hazırlanmış Temizlenmemiş girişini kullanarak bile .

Açıkçası , kodunuzun ne tükettiği üzerinde biraz kontrol sahibi olmak için girişi her zaman sterilize etmeniz gerekir .

muhakeme

Geliştirici kodlamamış olsa bile istemci istediği herhangi bir kodu çalıştırabilir; Bu sadece değerlendirilenler için değil , kendine yapılan çağrı için evalde geçerlidir .


2

Eval () kullanmanız gereken tek örnek, dinamik JS'yi anında çalıştırmanız gerektiğidir. Sunucudan eşzamansız olarak indirdiğiniz JS'den bahsediyorum ...

... Ve 10 kez 9 kez yeniden düzenleyerek bunu kolayca önleyebilirsiniz.


Günümüzde JavaScript'i sunucudan eşzamansız olarak yüklemenin başka (ve daha iyi) yolları vardır: w3bits.com/async-javascript
Ruud Helderman

1

evalnadiren doğru seçimdir. Bir betiği bir araya getirerek ve anında çalıştırarak başarmanız gerekenleri gerçekleştirebileceğiniz çok sayıda örnek olsa da, genellikle emrinizde çok daha güçlü ve sürdürülebilir tekniklere sahipsiniz: çağrışımlı dizi gösterimi ( obj["prop"]aynıdır obj.prop) , kapaklar, nesne yönelimli teknikler, fonksiyonel teknikler - bunları kullanın.


1

Istemci komut dosyası giderken, güvenlik meselesinin tartışmalı bir nokta olduğunu düşünüyorum. Tarayıcıya yüklenen her şey manipülasyona tabidir ve bu şekilde ele alınmalıdır. JavaScript kodunu yürütmenin ve / veya DOM'da tarayıcınızdaki URL çubuğu gibi nesneleri işlemenin çok daha kolay yolları olduğunda bir eval () ifadesi kullanmanın riski yoktur.

javascript:alert("hello");

Birisi DOM'unu manipüle etmek istiyorsa, sallanıyorum diyorum. Her türlü saldırıyı önlemek için güvenlik her zaman sunucu uygulamasının sorumluluğu olmalıdır, dönem.

Pragmatik açıdan bakıldığında, bir şeylerin başka türlü yapılabileceği bir durumda bir eval () kullanmanın faydası yoktur. Bununla birlikte, bir değerlendirmenin kullanılması gereken özel durumlar vardır. Bu durumda, kesinlikle sayfanın havaya uçması riski olmadan yapılabilir.

<html>
    <body>
        <textarea id="output"></textarea><br/>
        <input type="text" id="input" />
        <button id="button" onclick="execute()">eval</button>

        <script type="text/javascript">
            var execute = function(){
                var inputEl = document.getElementById('input');
                var toEval = inputEl.value;
                var outputEl = document.getElementById('output');
                var output = "";

                try {
                    output = eval(toEval);
                }
                catch(err){
                    for(var key in err){
                        output += key + ": " + err[key] + "\r\n";
                    }
                }
                outputEl.value = output;
            }
        </script>
    <body>
</html>

6
Re "Javascript yürütmek ve / veya DOM'da nesneleri işlemek için çok daha kolay yollar olduğunda bir eval () deyimi kullanmak için sıfır risk vardır". Kod yerleştirme, bir kullanıcı daha sonra başka bir kullanıcının tarayıcısında çalıştırılan kodu girebildiğinde bir sorundur. Tarayıcı konsolları tek başına bir kullanıcının başka bir kullanıcının tarayıcısında kod çalıştırmasına izin vermez, bu nedenle kod enjeksiyonuna karşı korumaya değip değmeyeceğine karar verirken ilgisizdir.
Mike Samuel

<head></head>Boş olsa bile gerekli değil mi?
Peter Mortensen

2
Bu cevap XSS risklerini tamamen görmezden geliyor .
Ruud Helderman

1

Sunucu tarafında, sql veya influxdb veya mongo gibi harici komut dosyaları ile uğraşırken eval yararlıdır. Hizmetlerinizi yeniden dağıtmadan çalışma zamanında özel doğrulama yapılabilir.

Örneğin, aşağıdaki meta verilere sahip bir başarı hizmeti

{
  "568ff113-abcd-f123-84c5-871fe2007cf0": {
    "msg_enum": "quest/registration",
    "timely": "all_times",
    "scope": [
      "quest/daily-active"
    ],
    "query": "`SELECT COUNT(point) AS valid from \"${userId}/dump/quest/daily-active\" LIMIT 1`",
    "validator": "valid > 0",
    "reward_external": "ewallet",
    "reward_external_payload": "`{\"token\": \"${token}\", \"userId\": \"${userId}\", \"amountIn\": 1, \"conversionType\": \"quest/registration:silver\", \"exchangeProvider\":\"provider/achievement\",\"exchangeType\":\"payment/quest/registration\"}`"
  },
  "efdfb506-1234-abcd-9d4a-7d624c564332": {
    "msg_enum": "quest/daily-active",
    "timely": "daily",
    "scope": [
      "quest/daily-active"
    ],
    "query": "`SELECT COUNT(point) AS valid from \"${userId}/dump/quest/daily-active\" WHERE time >= '${today}' ${ENV.DAILY_OFFSET} LIMIT 1`",
    "validator": "valid > 0",
    "reward_external": "ewallet",
    "reward_external_payload": "`{\"token\": \"${token}\", \"userId\": \"${userId}\", \"amountIn\": 1, \"conversionType\": \"quest/daily-active:silver\", \"exchangeProvider\":\"provider/achievement\",\"exchangeType\":\"payment/quest/daily-active\"}`"
  }
}

Hangi sonra izin,

  • Nesnelerin / değerlerin bir json'da değişmez dizeye doğrudan enjeksiyonu, metinlerin ayarlanması için yararlı

  • Karşılaştırıcı olarak kullanılabilir, diyelim ki CMS'deki görevi veya olayları nasıl doğrulayacağımız konusunda kurallar koyuyoruz

Bunun con:

  • Tam olarak test edilmezse, koddaki hatalar olabilir ve hizmetteki şeyleri parçalayabilir.

  • Bir bilgisayar korsanı sisteminize komut dosyası yazabilirse, o zaman hemen hemen berbatsınız.

  • Komut dosyanızı doğrulamanın bir yolu, komut dosyalarınızın karmasını güvenli bir yerde tutmaktır, böylece çalıştırmadan önce kontrol edebilirsiniz.


Güzel. Soruyu sorduğumda sunucu tarafı JS'yi bile düşünmemiştim.
Richard Turner

1

Bence haklı bir değerlendirme vakası nadir görülür. Bunu haklı olduğunu düşündüğünüzden, aslında haklı olduğunda kullandığınızdan daha fazla kullanabilirsiniz .

Güvenlik sorunları en iyi bilinenlerdir. Ancak JavaScript'in JIT derlemesini kullandığını ve bunun eval ile çok kötü çalıştığını da unutmayın. Eval, derleyiciye bir kara kutu gibidir ve JavaScript'in performans optimizasyonlarını ve kapsamını güvenli ve doğru bir şekilde uygulamak için kodu (bir dereceye kadar) önceden tahmin edebilmesi gerekir. Bazı durumlarda, performans etkisi eval dışındaki diğer kodları bile etkileyebilir.

Daha fazla bilgi edinmek istiyorsanız: https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20%26%20closures/ch2.md#eval


0

İşleve geçirilen kod üzerinde tam kontrole sahipseniz kullanmakta sorun yoktur eval.


2
Ne geçtiğiniz üzerinde tam kontrole sahipseniz eval, büyük soru, bunun gerçek JS yerine bir dize olması ne zaman mantıklı olur?
cHao

@cHao Örneğin, büyük bir Oyun Uygulamanız (5-10MB Javascript) varsa, önce bir Yükleme- Bar ya da benzeri bir şey. İndirdikten sonra, yüklü Game-Application-Script'i çalıştırmak için "eval (kaynak)" veya daha iyi "new Function (kaynak)" kullanabilirsiniz. Bu şekilde kullanıcı, uygulamanın başlayabilmesi için Uygulamanın indirilmesi için zamana ihtiyacı olduğunu görsel olarak görebilir. Bu olmadan, kullanıcı görsel olarak geri bildirim olmadan tüm Uygulamanın yüklenmesini beklemek zorundadır.
SammieFox

@SammieFox Bunu yapmanın başka (ve daha iyi) yolları var, en önemlisi <script async="true" src="...">. Ayrıca bakınız: w3bits.com/async-javascript
Ruud Helderman

Cevap tehlikeli bir tavsiye; çok fazla geliştiricinin yanlış kontrol sahibi olma duygusu var. Tavsiye , artık aktif olarak korunmayan yazılımlar için bir anlam ifade ediyor. Ancak bu tür yazılımlar ölü sayılmalıdır.
Ruud Helderman

0

Sadece mümkünse test sırasında. Eval () 'nin diğer uzmanlaşmış JSON vb. Değerlendiricilerden çok daha yavaş olduğunu da unutmayın.


0

Kodun kaynağının sizden veya gerçek kullanıcıdan geldiğinden emin olabileceğiniz sürece eval () işlevini kullanmamanız için hiçbir neden yoktur. Eval () işlevine gönderilenleri değiştirebilmesine rağmen, bu bir güvenlik sorunu değildir, çünkü web sitesinin kaynak kodunu değiştirebilir ve bu nedenle JavaScript kodunun kendisini değiştirebilir.

Peki ... ne zaman eval () kullanılmamalıdır? Eval () sadece üçüncü bir tarafın değiştirme şansı olduğunda kullanılmamalıdır. İstemci ile sunucunuz arasındaki bağlantıyı kesmek gibi (ancak bu bir sorunsa HTTPS kullanın). Bir forumda olduğu gibi başkaları tarafından yazılan kodu ayrıştırmak için değerlendirme yapmamalısınız ().


Re "Kodun kaynağının sizden veya gerçek kullanıcıdan geldiğinden emin olabileceğiniz sürece eval () işlevini kullanmamanız için hiçbir neden yoktur." Bu, tek bir kullanıcı olduğunu varsayar. Bu öneri OP'de belirtilmemiştir. Birden fazla kullanıcı olduğunda, evalbir kullanıcının içeriğinden oluşan bir dize dikkatsizce bu kullanıcının diğer kullanıcının tarayıcısında kod yürütmesine izin verebilir.
Mike Samuel

@MikeSamuel, eval diğer kullanıcının tarayıcısında kod yürütebilir, bunu duymadım, bunu denediniz mi? Göz atma tarihinde bu hiç olmadı, bize bir örnek gösterebilir misiniz?
Akash Kava

@AkashKava, Bir dize bir kullanıcı aracısından kaynaklanabilir, bir veritabanında saklanabilir ve daha sonra başka bir tarayıcıya sunulabilir eval. Bu her zaman olur.
Mike Samuel

@MikeSamuel veritabanı? nerede? kim yanlış dize hizmet vermektedir? Suçu sunucu tarafında veritabanı değil mi? her şeyden önce EVAL kötü yazılmış sunucu tarafı kodu için suçlanmamalıdır. Jsfiddle kullanın ve dünyaya zarar verebileceği gerçek bir dünya örneği gösterin.
Akash Kava

2
@AkashKava, sorunuzu anlamıyorum. Belirli bir uygulamadan bahsetmiyoruz, ancak kullanılmama nedenleri eval. Sunucuyu suçlamak ne kadar yararlı? Birisi suçlanmalı, saldırgan olmalı. Suçlamadan bağımsız olarak, sunucudaki hatalara rağmen XSS'ye karşı savunmasız olmayan bir istemci, savunmasız olan ve diğer her şey eşit olan bir istemciden daha iyidir.
Mike Samuel

0

Gerçekten ihtiyaç varsa eval kötü değildir. Ama rastlarsanız o eval kullanımlarından% 99.9 olan değil (setTimeout şeyler hariç) gerekli.

Benim için kötülük bir performans, hatta bir güvenlik sorunu değil (iyi, dolaylı olarak her ikisi de). Eval'in tüm bu gereksiz kullanımları bir bakım cehennemine ekler. Yeniden düzenleme araçları atılır. Kod aramak zor. Bu evallerin beklenmedik etkileri lejyon.


5
setTimeout için eval gerekli değildir. Burada bir işlev referansı da kullanabilirsiniz.
Matthew Crumley

0

JavaScript'in eval () değeri ne zaman kötü değildir?

Ben her zaman eval kullanmaktan vazgeçmeye çalışıyorum . Neredeyse her zaman daha temiz ve bakımı kolay bir çözüm mevcuttur. JSON ayrıştırması için bile Eval'a gerek yoktur . Eval bakım cehennemine ekler . Sebepsiz değil, Douglas Crockford gibi ustalar tarafından kaşlarını çattı.

Ama kullanılması gereken bir örnek buldum :

İfadeyi iletmeniz gerektiğinde.

Örneğin, ben genel yapıları bir işlevi var google.maps.ImageMapTypebenim için nesne, ama gelen kiremit URL oluşturabilir nasıl, o tarifi anlatmaya gerek zoomve coordparametreler:

my_func({
    name: "OSM",
    tileURLexpr: '"http://tile.openstreetmap.org/"+b+"/"+a.x+"/"+a.y+".png"',
    ...
});

function my_func(opts)
{
    return new google.maps.ImageMapType({
        getTileUrl: function (coord, zoom) {
            var b = zoom;
            var a = coord;
            return eval(opts.tileURLexpr);
        },
        ....
    });
}

3
Bu, eval () gerekmediği için yeniden düzenlenebilir gibi görünüyor - tileURLexpr sadece bir şablon olduğundan, replace () 'in bazı makul kullanımı işi yapacaktır. Yine de, soruyu gönderdiğimde, bir kullanıcının e-tablo işlevine benzer şekilde değerlendirilecek bir matematiksel formül belirtmesine izin vermekle ilgili olduğunu düşündüğüm bir örneği hatırlatıyor. Elbette o zaman bahsetmedim çünkü cevapları etkilemek istemedim!
Richard Turner

8
tileURL: function (zoom, coord) { return 'http://tile.openstreetmap.org/' + b + '/' + a.x + '/' + a.y + '.png'; },
Casey Chu

0

Benim kullanma örneğim eval: import .

Genellikle nasıl yapılır.

var components = require('components');
var Button = components.Button;
var ComboBox = components.ComboBox;
var CheckBox = components.CheckBox;
...
// That quickly gets very boring

Ancak yardımı evalve küçük bir yardımcı işlevi ile çok daha iyi bir görünüm elde edilir:

var components = require('components');
eval(importable('components', 'Button', 'ComboBox', 'CheckBox', ...));

importable gibi görünebilir (bu sürüm somut üyelerin içe aktarılmasını desteklemez).

function importable(path) {
    var name;
    var pkg = eval(path);
    var result = '\n';

    for (name in pkg) {
        result += 'if (name !== undefined) throw "import error: name already exists";\n'.replace(/name/g, name);
    }

    for (name in pkg) {
        result += 'var name = path.name;\n'.replace(/name/g, name).replace('path', path);
    }
    return result;
}

2
Fikir için 1, ama burada bir hata vardır: .replace(/name/g, name).replace('path', path). Eğer namedize içeriyorsa "path"sürprizlerle karşılaşabilirsiniz.
wberry

1
Her özelliği için bir değişken bildirmek componentsolası bir kod kokusudur; kodunuzu yeniden düzenlemek 'sorunu' tamamen ortadan kaldırabilir. Mevcut çözümünüz sadece sözdizimsel şekerdir. Bunu yapmakta ısrar ederseniz, dağıtımdan önce yürütülecek kendi ön işlemcinizi yazmanızı öneririm. Bu evalüretim kodundan uzak durmalıdır .
Ruud Helderman

0

Eval kötü değil, sadece yanlış kullanıldı.

Kodu içine girerek oluşturduysanız veya ona güvenebiliyorsanız, sorun değil. Kullanıcılar, kullanıcı girişinin eval ile nasıl bir önemi olmadığını konuşurlar. Şey ~

Sunucuya giden kullanıcı girdisi varsa, istemciye geri döner ve bu kod, dezenfekte edilmeden değerlendirmede kullanılır. Tebrikler, kullanıcı verilerinin herkese gönderilmesi için pandora'nın kutusunu açtınız.

Değerlendirmenin bulunduğu yere bağlı olarak, birçok web sitesi SPA'ları kullanır ve eval, aksi takdirde kolay olmayacak uygulama içlerine erişmeyi kolaylaştırabilir. Şimdi, bu değerlendirmeyi bantlayabilen ve verileri tekrar çalabilen sahte bir tarayıcı uzantısı yapabilirler.

Sadece eval'i kullanarak amacının ne olduğunu bulmalısın. Bu tür şeyleri yapmak, nesne kullanmak veya benzerlerini yapmak için yöntemler yapabildiğinizde kod üretmek gerçekten ideal değildir.

Şimdi eval kullanımına güzel bir örnek. Sunucunuz, oluşturduğunuz swagger dosyasını okuyor. URL parametrelerinin birçoğu biçiminde oluşturulur {myParam}. Bu nedenle, URL'leri okumak ve daha sonra çok sayıda uç noktanız olduğu için karmaşık değişiklikler yapmak zorunda kalmadan bunları şablon dizelerine dönüştürmek istersiniz. Yani böyle bir şey yapabilirsiniz. Bunun çok basit bir örnek olduğunu unutmayın.

const params = { id: 5 };

const route = '/api/user/{id}';
route.replace(/{/g, '${params.');

// use eval(route); to do something

-1

Kod üretimi. 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ırıp 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({}))

Bunun eval()gibi bir durumda performansı da bir sorun oluşturmaz, çünkü oluşturulan dizeyi yalnızca bir kez yorumlamanız ve ardından yürütülebilir çıktıyı birçok kez yeniden kullanmanız gerekir.

Burada merak ediyorsanız kod oluşturma işleminin nasıl gerçekleştirildiğini görebilirsiniz .


"Hiper metin önce bir dize olarak oluşturulur (...)" Derleme aşamasında tüm kod oluşturma işlemlerini yapmak, ortaya çıkan hiper metin kodunu ayrı bir yürütülebilir (.js) dosyaya yazmak, ardından bu dosyayı test etmek ve dağıtmak için daha anlamlı olur. üretim. Kod oluşturma yönteminizi seviyorum. Sadece işte evalderleme zamanında aittir bazı sorumluluk, çalışma zamanı içine taşındığını bir ipucu.
Ruud Helderman

-1

İnancım, eval istemci tarafı web uygulamaları için çok güçlü bir fonksiyon ve güvenli ... JavaScript kadar güvenli değil. :-) Güvenlik sorunları aslında sunucu tarafı sorunudur, çünkü şimdi Firebug gibi bir araçla herhangi bir JavaScript uygulamasına saldırabilirsiniz.


1
Kullanımın evalXSS saldırılarına karşı güvence altına alınması gerekir, bu da her zaman doğru değildir.
Benjamin

-1

Eval, makrolarınız olmadığında kod üretimi için kullanışlıdır.

(Aptal) bir örnek için, bir Brainfuck derleyicisi yazıyorsanız , büyük olasılıkla komut dizisini dize olarak gerçekleştiren bir işlev oluşturmak ve onu bir işlev döndürecek şekilde değerlendirmek istersiniz.


Ya bir derleyici yazarsınız (oluşturulan kodu yürütmek yerine kaydeder) ya da bir yorumlayıcı yazarsınız (her komutun önceden derlenmiş bir uygulaması vardır). Bunun için de bir kullanım durumu söz konusu değildir eval.
Ruud Helderman

Javascript kodu oluşturduysanız ve hemen uygulamak istiyorsanız (diyelim ki doğrudan yorumlamaya göre performans avantajları için), bu eval için bir kullanım örneği olacaktır.
Erik Haliewicz

İyi bir nokta; Bu makalede Blockly ile ilgili bir örnek gördüm . evalAlternatif ( İşlev ) hem daha hızlı ( MDN'de açıklandığı gibi ) hem de daha güvenilir olduğunda (üretilen kod ile aynı web sayfasındaki diğer 'destekleyici' kod arasında daha iyi bir izolasyonla öngörülemeyen hataları önler ), Google'ı öneririm .
Ruud Helderman

-5

Bir ayrıştırma işleviyle (örneğin, jQuery.parseJSON) bir JSON yapısını ayrıştırdığınızda, JSON dosyasının mükemmel bir yapısını bekler (her özellik adı çift tırnak içine alınır). Ancak, JavaScript daha esnektir. Bu nedenle, bundan kaçınmak için eval () kullanabilirsiniz.


4
Körü körüne kullanmayın eval, esp. üçüncü taraf bir kaynaktan JSON verileri alınırken. Özellikler üzerinde tırnak olmadan JSON.Stringify bakın ? "alıntı anahtar adları olmadan JSON" ayrıştırma doğru yaklaşım için.
Rob W

2
Özellik adlarının çevresinde çift tırnak kullanmazsa, bir nesne değişmezinin dize ile temsili olabilir, ancak JSON değildir . JSON özellik adlarını stringa stringolarak tanımlar ve a , ters eğik çizgi kaçışlarını kullanarak çift tırnak içine alınmış sıfır veya daha fazla Unicode karakter dizisi
Yararsız Kod

Nikolas Zakas'ın makalesine bakın - "eval () kötü değil, sadece yanlış anlaşıldı" nczonline.net/blog/2013/06/25/eval-isnt-evil-just-misunderstood
vitmalina

@vitmalina Zakas'ın makalesinden: "Bu, kullanıcı girdisi alıp eval () üzerinden çalıştırıyorsanız tehlikeli olabilir. Ancak, girdiniz kullanıcıdan gelmiyorsa, gerçek bir tehlike var mı?" Sorun tam olarak bu. Kodunuz 'merhaba dünya' oranlarının ötesine geçtikten sonra, kullanıcı girdisine sızmadığınızı kanıtlamak hemen imkansız hale gelir eval. Herhangi bir ciddi çok kiracılı web uygulamasında, düzinelerce geliştirici aynı kod tabanı üzerinde çalışıyorsa, bu kabul edilemez.
Ruud Helderman
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.