Tại sao sử dụng hàm eval JavaScript là một ý tưởng tồi?


534

Hàm eval là một cách mạnh mẽ và dễ dàng để tạo mã động, vậy các cảnh báo là gì?


92
Đừng bị đánh giá () bởi Simon Willison - 24ways.org/2005/dont-be-eval
Brian Singh

5
Như được phác thảo trong moduscreate.com/javascript-performance-tips-tricks - (Hàm mới (str)) () có hiệu suất cao hơn eval (str). Chỉ 2 xu của tôi :)
Grgur

3
rõ ràng fcuntion mới (a) chậm hơn 67% so với eval (a) trên chrome
giấc ngủ

đối với tôi các chức năng mới (a) chậm hơn 80% trên chrome mới nhất trên osx
john Smith

3
Tôi đã thêm một hàm tĩnh, chỉ để so sánh hiệu suất. jsperf.com/eval-vs-new-feft/2
Nepoxx

Câu trả lời:


386
  1. Việc sử dụng eval không đúng cách sẽ mở ra mã của bạn cho các cuộc tấn công tiêm chích

  2. Gỡ lỗi có thể khó khăn hơn (không có số dòng, v.v.)

  3. mã eval'd thực thi chậm hơn (không có cơ hội biên dịch / bộ đệm mã eval'd)

Chỉnh sửa: Như @Jeff Walden đã chỉ ra trong các bình luận, # 3 ngày nay ít đúng hơn so với năm 2008. Tuy nhiên, trong khi một số bộ đệm của các tập lệnh được biên dịch có thể xảy ra, điều này sẽ chỉ giới hạn ở các tập lệnh được lặp đi lặp lại mà không sửa đổi. Một kịch bản có khả năng hơn là bạn đang đánh giá các tập lệnh đã trải qua sửa đổi nhỏ mỗi lần và như vậy không thể được lưu trữ. Chúng ta hãy nói rằng MỘT SỐ mã eval'd thực thi chậm hơn.


2
@JeffWalden, bình luận tuyệt vời. Tôi đã cập nhật bài viết của mình mặc dù tôi nhận ra rằng đã một năm kể từ khi bạn đăng. Xnzo72, nếu bạn đã đủ điều kiện nhận xét của mình (như Jeff đã làm) thì tôi có thể đồng ý với bạn. Jeff đã chỉ ra chìa khóa: "eval của cùng một chuỗi nhiều lần có thể tránh được phân tích cú pháp". Như nó là, bạn chỉ sai; # 3 đúng với nhiều kịch bản.
Prestaul

7
@Prestaul: Vì kẻ tấn công được cho là có thể sử dụng bất kỳ công cụ phát triển nào để thay đổi JavaScript trong máy khách, tại sao bạn lại nói Eval () mở mã của bạn để tấn công tiêm chích? Chưa mở? (Tất nhiên tôi đang nói về JavaScript của khách hàng)
Eduardo Molteni

60
@EduardoMolteni, chúng tôi không quan tâm (và thực sự không thể ngăn chặn) người dùng thực thi js trong trình duyệt của riêng họ. Các cuộc tấn công mà chúng tôi đang cố gắng tránh là khi người dùng cung cấp các giá trị được lưu, sau đó được đặt vào javascript và eval'd. Ví dụ: tôi có thể đặt tên người dùng của mình thành: badHackerGuy'); doMaliciousThings();và nếu bạn lấy tên người dùng của mình, hãy ghép nó thành một số tập lệnh và loại bỏ nó trong trình duyệt của người khác thì tôi có thể chạy bất kỳ javascript nào tôi muốn trên máy của họ (ví dụ: buộc họ phải +1 bài đăng của tôi, đăng dữ liệu của họ lên máy chủ của tôi, v.v.)
Prestaul

3
Nói chung, # 1 đúng với khá nhiều, nếu không phải hầu hết các lệnh gọi hàm. eval () không nên bị chỉ trích và tránh bởi các lập trình viên có kinh nghiệm, chỉ vì các lập trình viên thiếu kinh nghiệm lạm dụng nó. Tuy nhiên, các lập trình viên có kinh nghiệm thường có kiến ​​trúc tốt hơn trong mã của họ và eval () sẽ hiếm khi được yêu cầu hoặc thậm chí nghĩ đến do kiến ​​trúc tốt hơn này.
frodeborli

4
@TamilVendhan Chắc chắn bạn có thể đặt điểm dừng. Bạn có thể truy cập tệp ảo do Chrome tạo để mã hóa bằng cách thêm debugger;câu lệnh vào mã nguồn của bạn. Điều này sẽ dừng việc thực hiện chương trình của bạn trên dòng đó. Sau đó, bạn có thể thêm các điểm dừng gỡ lỗi giống như nó chỉ là một tệp JS khác.
Sid

346

eval không phải lúc nào cũng xấu xa. Có những lúc nó hoàn toàn thích hợp.

Tuy nhiên, eval hiện đang được sử dụng ồ ạt bởi những người không biết họ đang làm gì. Điều đó bao gồm những người viết hướng dẫn JavaScript, thật không may, và trong một số trường hợp, điều này thực sự có thể có hậu quả bảo mật - hoặc, thường xuyên hơn, các lỗi đơn giản. Vì vậy, chúng ta càng có thể làm để ném một dấu hỏi lên eval, thì càng tốt. Bất cứ khi nào bạn sử dụng eval, bạn cần phải tỉnh táo - kiểm tra xem bạn đang làm gì, bởi vì rất có thể bạn có thể thực hiện nó một cách tốt hơn, an toàn hơn, sạch sẽ hơn.

Để đưa ra một ví dụ quá điển hình, để đặt màu của một phần tử với id được lưu trong biến 'khoai tây':

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

Nếu các tác giả của loại mã ở trên có manh mối về những điều cơ bản về cách thức hoạt động của các đối tượng JavaScript, thì họ đã nhận ra rằng dấu ngoặc vuông có thể được sử dụng thay cho tên dấu chấm bằng chữ, tránh sự cần thiết của eval:

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

... dễ đọc hơn cũng như ít lỗi hơn.

(Nhưng sau đó, một người / thực sự / biết những gì họ đang làm sẽ nói:

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

đáng tin cậy hơn thủ thuật cũ tinh ranh khi truy cập các phần tử DOM ngay từ đối tượng tài liệu.)


82
Hmm, đoán tôi đã gặp may khi lần đầu tiên học JavaScript. Tôi luôn sử dụng "document.getEuityById" để truy cập DOM; Trớ trêu thay, tôi chỉ làm điều đó vào thời điểm đó vì tôi không biết các đối tượng hoạt động như thế nào trong JavaScript ;-)
Mike Spross

5
đồng ý. Đôi khi eval vẫn ổn, ví dụ như phản hồi JSON từ dịch vụ web
schoetbi

40
@schoetbi: Bạn không nên sử dụng JSON.parse()thay vì eval()cho JSON?
nyuszika7h

4
@bobince code.google.com/p/json-sans-eval hoạt động trên tất cả các trình duyệt, github.com/douglascrockford/JSON-js cũng vậy . Json2.js của Doug Crockford không sử dụng eval trong nội bộ, nhưng có séc. Ngoài ra, nó tương thích về phía trước với hỗ trợ trình duyệt tích hợp cho JSON.
Martijn

8
@ bobince Có một cái gì đó gọi là tính năng phát hiện và polyfills để xử lý thiếu thư viện JSON và những thứ khác (xem modernizr.com )
MauganRa

37

Tôi tin rằng vì nó có thể thực thi bất kỳ hàm JavaScript nào từ một chuỗi. Sử dụng nó giúp mọi người dễ dàng tiêm mã lừa đảo vào ứng dụng.


5
Thay thế sau đó là gì?
hiện đại

5
Thực sự thay thế chỉ là viết mã mà không yêu cầu nó. Crockford đi sâu vào vấn đề này, và nếu bạn cần sử dụng nó, anh ta nói khá nhiều rằng đó là một lỗi thiết kế chương trình và cần phải được làm lại. Sự thật, tôi cũng đồng ý với anh ấy. JS cho tất cả các sai sót của nó là rất linh hoạt và cho phép rất nhiều chỗ để làm cho nó linh hoạt.
kemiller2002

3
Không đúng, hầu hết các khung công tác đều có phương pháp phân tích JSON và nếu bạn không sử dụng khung, bạn có thể sử dụng JSON.parse (). Hầu hết các trình duyệt đều hỗ trợ nó và nếu bạn thực sự gặp khó khăn, bạn có thể viết một trình phân tích cú pháp cho JSON khá dễ dàng.
kemiller2002

6
Tôi không mua đối số này, vì đã dễ dàng đưa mã lừa đảo vào ứng dụng Javascript. Chúng tôi có bảng điều khiển trình duyệt, phần mở rộng tập lệnh, v.v ... Mỗi đoạn mã được gửi cho máy khách là tùy chọn để máy khách thực thi.
dùng2867288

6
Vấn đề là tôi dễ dàng tiêm mã vào trình duyệt của bạn hơn. Giả sử bạn đang sử dụng eval trên chuỗi truy vấn. Nếu tôi lừa bạn nhấp vào một liên kết đến trang web đó với chuỗi truy vấn của tôi được đính kèm, thì tôi đã thực thi mã của mình trên máy của bạn với sự cho phép đầy đủ từ trình duyệt. Tôi muốn đăng nhập tất cả mọi thứ bạn gõ trên trang web đó và gửi cho tôi? Xong và không có cách nào ngăn tôi vì khi eval thực thi, trình duyệt sẽ trao cho nó quyền cao nhất.
kemiller2002 4/2/2015

27

Hai điểm đến trong tâm trí:

  1. Bảo mật (nhưng miễn là bạn tạo chuỗi để tự đánh giá, đây có thể không phải là vấn đề)

  2. Hiệu suất: cho đến khi mã được thực thi là không xác định, nó không thể được tối ưu hóa. (về javascript và hiệu suất, chắc chắn là bài thuyết trình của Steve Yegge )


9
Tại sao bảo mật là một vấn đề nếu khách hàng dù sao cũng có thể làm với mã của chúng tôi bất cứ điều gì anh ấy / cô ấy muốn? Greasemonkey?
Paul Brewczynski

2
@PaulBrewczynski, vấn đề bảo mật xuất hiện khi người dùng A lưu một phần mã của mình để được evalxử lý và sau đó, đoạn mã nhỏ đó chạy trên trình duyệt B của người dùng
Felipe Pereira

21

Truyền đầu vào của người dùng vào eval () là một rủi ro bảo mật, nhưng mỗi lần gọi eval () tạo ra một phiên bản mới của trình thông dịch JavaScript. Đây có thể là một con heo tài nguyên.


27
Trong hơn 3 năm kể từ khi tôi trả lời điều này, sự hiểu biết của tôi về những gì xảy ra, hãy nói, đã sâu sắc hơn. Những gì thực sự xảy ra là một bối cảnh thực hiện mới được tạo ra. Xem dmitrysoshnikov.com/ecmascript/ch CHƯƠNG
Andrew Hedges

20

Nó thường chỉ là một vấn đề nếu bạn chuyển đầu vào của người dùng eval.


16

Chủ yếu, nó khó hơn rất nhiều để duy trì và gỡ lỗi. Nó giống như một goto. Bạn có thể sử dụng nó, nhưng nó khiến việc tìm kiếm vấn đề trở nên khó khăn hơn và khó hơn đối với những người có thể cần thực hiện thay đổi sau này.


Eval có thể được sử dụng để thay thế các tính năng siêu lập trình bị thiếu, như các mẫu. Tôi thích cách máy phát điện nhỏ gọn hơn danh sách chức năng vô tận theo chức năng.
franespase

Miễn là chuỗi không đến từ người dùng hoặc bị giới hạn trong trình duyệt bạn có thể. JavaScript có rất nhiều sức mạnh lập trình siêu dữ liệu bằng cách sử dụng các công cụ như thay đổi nguyên mẫu, obj [thành viên], Proxy, json.parse, cửa sổ, hàm trang trí (trạng từ) trong đó newf = decorator (oldf), hàm bậc cao hơn như Array.prototype.map (f) , chuyển đối số cho các hàm khác, đối số từ khóa thông qua {}. Bạn có thể cho tôi biết một trường hợp sử dụng mà bạn không thể làm những việc này thay vì eval không?
aoeu256

13

Một lưu ý là bạn thường có thể sử dụng eval () để thực thi mã trong môi trường bị hạn chế khác - các trang web mạng xã hội chặn các hàm JavaScript cụ thể đôi khi có thể bị đánh lừa bằng cách phá vỡ chúng trong một khối eval -

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

Vì vậy, nếu bạn đang tìm cách chạy một số mã JavaScript, nơi nó có thể không được phép ( Myspace , tôi đang nhìn bạn ...) thì eval () có thể là một mẹo hữu ích.

Tuy nhiên, vì tất cả các lý do đã đề cập ở trên, bạn không nên sử dụng nó cho mã của riêng mình, nơi bạn có toàn quyền kiểm soát - điều đó là không cần thiết và tốt hơn là nên chuyển sang kệ 'hack JavaScript lừa đảo'.


1
Chỉ cần cập nhật mã ở trên .. --hi đó! - cần phải được trích dẫn vì nó là một chuỗi. eval ('al' + 'er' + 't (' + '"xin chào!"' + ')');
Mahesh

2
[]["con"+"struc"+"tor"]["con"+"struc"+"tor"]('al' + 'er' + 't(\'' + 'hi there!' + '\')')()
Konrad Borowski

4
Rất tiếc, có những trang mạng xã hội hạn chế cảnh báo () nhưng cho phép eval ()?!
joshden

12

Trừ khi bạn để eval () một nội dung động (thông qua cgi hoặc đầu vào), nó sẽ an toàn và vững chắc như tất cả các JavaScript khác trong trang của bạn.


Mặc dù điều này là đúng - nếu nội dung của bạn không năng động, lý do nào để sử dụng eval cho nó? Bạn chỉ có thể đặt mã trong một hàm và gọi nó, thay vào đó!
Periata Breatta

Ví dụ: để phân tích giá trị trả về (như JSON, các chuỗi do máy chủ xác định, v.v.) xuất phát từ lệnh gọi Ajax.
Thevs

2
Ồ, tôi hiểu rồi. Tôi sẽ gọi những người năng động đó bởi vì khách hàng không biết trước họ là ai, nhưng tôi hiểu ý của bạn bây giờ.
Periata Breatta

7

Cùng với phần còn lại của câu trả lời, tôi không nghĩ rằng các tuyên bố tệ hại có thể được giảm thiểu nâng cao.


6

Đó là một rủi ro bảo mật có thể xảy ra, nó có phạm vi thực thi khác và khá kém hiệu quả, vì nó tạo ra một môi trường tập lệnh hoàn toàn mới để thực thi mã. Xem ở đây để biết thêm thông tin: eval .

Tuy nhiên, nó khá hữu ích và được sử dụng có chừng mực có thể bổ sung rất nhiều chức năng tốt.


5

Trừ khi bạn chắc chắn 100% rằng mã được đánh giá là từ một nguồn đáng tin cậy (thường là ứng dụng của riêng bạn), thì đó là cách chắc chắn để đưa hệ thống của bạn vào một cuộc tấn công kịch bản chéo trang.


1
Chỉ khi bảo mật phía máy chủ của bạn hút. Bảo mật phía khách hàng là vô nghĩa.
doubleOrt

5

Tôi biết cuộc thảo luận này đã cũ, nhưng tôi thực sự thích cách tiếp cận này của Google và muốn chia sẻ cảm giác đó với những người khác;)

Một điều nữa là bạn càng hiểu rõ hơn Bạn càng cố gắng hiểu và cuối cùng Bạn không tin rằng điều gì đó tốt hay xấu chỉ vì ai đó nói vậy :) Đây là một video rất truyền cảm hứng giúp tôi suy nghĩ nhiều hơn :) THỰC HÀNH TỐT là tốt, nhưng đừng sử dụng chúng một cách thiếu suy nghĩ :)


1
Đúng. Tôi đã tìm thấy, cho đến nay ít nhất là trong Chrome, một trường hợp sử dụng dường như hiệu quả hơn. Chạy RAF mà bỏ qua một chuỗi trong một biến đã cho mỗi lần lặp. Sử dụng setInterval để chỉ đặt những thứ được định hướng bằng đồ họa như cài đặt biến đổi, v.v. trong chuỗi đó. Tôi đã thử nhiều cách tiếp cận khác như lặp qua các hàm trong một mảng hoặc sử dụng một biến để chỉ đặt các biến đổi cho các phần tử được thay đổi, nhưng cho đến nay điều này có vẻ hiệu quả nhất. Khi nói đến hoạt hình, bài kiểm tra chân thực nhất là đôi mắt của bạn.
jdmayfield

5

Nó không hẳn là xấu với điều kiện bạn biết bạn đang sử dụng bối cảnh nào.

Nếu ứng dụng của bạn đang sử dụng eval()để tạo một đối tượng từ một số JSON đã quay trở lại từ XMLHttpRequest đến trang web của riêng bạn, được tạo bởi mã phía máy chủ đáng tin cậy của bạn, thì đó có lẽ không phải là vấn đề.

Mã JavaScript phía máy khách không tin cậy dù sao cũng không thể làm được nhiều như vậy. Với điều kiện bạn đang thực hiện eval()đã đến từ một nguồn hợp lý, bạn vẫn ổn.


3
Không sử dụng eval chậm hơn là chỉ phân tích cú pháp JSON?
Brendan Long

@Qix - chạy thử nghiệm đó trên trình duyệt của tôi (Chrome 53) cho thấy eval nhanh hơn một chút so với phân tích cú pháp .
Periata Breatta

@PeriataBreatta Huh, lạ. Tôi tự hỏi tại sao. Tại thời điểm tôi nhận xét đó không phải là trường hợp. Tuy nhiên, Chrome không có gì lạ khi tăng hiệu suất lạ trong các khu vực nhất định của thời gian chạy từ phiên bản này sang phiên bản khác.
Qix - MONICA ĐƯỢC PHÂN BIỆT

Một chủ đề cũ nhỏ ở đây, nhưng từ những gì tôi đã đọc-- không khẳng định tôi đã tự mình truy tìm nó-- JSON.parse thực tế là đầu vào của nó trong giai đoạn cuối. Vì vậy, hiệu quả-khôn ngoan, mất nhiều công sức / thời gian. Nhưng an ninh-khôn ngoan, tại sao không chỉ phân tích? eval là một công cụ tuyệt vời. Sử dụng nó cho những thứ không có cách nào khác. Để truyền các hàm thông qua JSON, có một cách để làm điều đó mà không cần eval. Tham số thứ hai đó trong JSON.opesify cho phép bạn đặt một cuộc gọi lại để chạy mà bạn có thể kiểm tra thông qua typeof nếu đó là một hàm. Sau đó lấy hàm .toString (). Có một số bài viết tốt về điều này nếu bạn tìm kiếm.
jdmayfield


4

Nếu bạn muốn người dùng nhập một số hàm logic và đánh giá VÀ HOẶC thì hàm eval JavaScript là hoàn hảo. Tôi có thể chấp nhận hai chuỗi và eval(uate) string1 === string2, v.v.


Bạn cũng có thể sử dụng Hàm () {}, nhưng hãy cẩn thận khi sử dụng các chức năng này trên máy chủ trừ khi bạn muốn người dùng tiếp quản máy chủ của bạn hahahah.
aoeu256

3

Nếu bạn phát hiện ra việc sử dụng eval () trong mã của mình, hãy nhớ câu thần chú là eval () là ác.

Hàm này lấy một chuỗi tùy ý và thực thi nó dưới dạng mã JavaScript. Khi mã được đề cập được biết trước (không được xác định khi chạy), không có lý do để sử dụng eval (). Nếu mã được tạo động khi chạy, thường có cách tốt hơn để đạt được mục tiêu mà không cần eval (). Ví dụ: chỉ cần sử dụng ký hiệu ngoặc vuông để truy cập các thuộc tính động là tốt hơn và đơn giản hơn:

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

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

Việc sử dụng eval()cũng có ý nghĩa bảo mật, bởi vì bạn có thể đang thực thi mã (ví dụ: đến từ mạng) đã bị giả mạo. Đây là một phản mẫu phổ biến khi xử lý phản hồi JSON từ yêu cầu Ajax. Trong những trường hợp đó, tốt hơn là sử dụng các phương thức tích hợp sẵn của trình duyệt để phân tích phản hồi JSON để đảm bảo an toàn và hợp lệ. Đối với các trình duyệt không hỗ trợJSON.parse() nguyên bản, bạn có thể sử dụng thư viện từ JSON.org.

Điều quan trọng cần nhớ là việc truyền các chuỗi tới setInterval(), setTimeout()Function()phần lớn hàm tạo, tương tự như việc sử dụng eval()và do đó nên tránh.

Đằng sau hậu trường, JavaScript vẫn phải đánh giá và thực thi chuỗi bạn truyền dưới dạng mã lập trình:

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

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

Sử dụng hàm tạo Hàm () mới tương tự như eval () và cần được tiếp cận cẩn thận. Nó có thể là một cấu trúc mạnh mẽ nhưng thường bị sử dụng sai. Nếu bạn hoàn toàn phải sử dụng eval(), bạn có thể xem xét sử dụng Hàm () mới thay thế.

Có một lợi ích tiềm năng nhỏ vì mã được đánh giá trong Hàm mới () sẽ chạy trong phạm vi hàm cục bộ, do đó, bất kỳ biến nào được xác định bằng var trong mã được đánh giá sẽ không tự động trở thành toàn cục.

Một cách khác để ngăn chặn toàn cầu tự động là kết thúc eval()cuộc gọi thành một chức năng ngay lập tức.


Bạn có thể đề nghị làm thế nào tôi có thể đánh giá một tên biến động cục bộ mà không có eval không? Các chức năng của Eval (và tương tự) là giải pháp cuối cùng trong hầu hết các ngôn ngữ có chứa chúng, nhưng đôi khi điều đó là cần thiết. Trong trường hợp nhận được tên của biến động, có giải pháp nào an toàn hơn không? Trong mọi trường hợp, bản thân javascript không phải để bảo mật thực sự (phía máy chủ rõ ràng là phòng thủ chính). Nếu bạn quan tâm, đây là trường hợp sử dụng của tôi, tôi muốn thay đổi: stackoverflow.com/a/48294208
Joe thường xuyên

2

Bên cạnh các vấn đề bảo mật có thể xảy ra nếu bạn đang thực thi mã do người dùng gửi, hầu hết thời gian có một cách tốt hơn không liên quan đến việc phân tích lại mã mỗi khi mã được thực thi. Các hàm hoặc thuộc tính đối tượng ẩn danh có thể thay thế hầu hết việc sử dụng eval và an toàn hơn và nhanh hơn nhiều.


2

Điều này có thể trở thành một vấn đề khi thế hệ trình duyệt tiếp theo xuất hiện với một số hương vị của trình biên dịch JavaScript. Mã được thực thi thông qua Eval có thể không hoạt động tốt như phần còn lại của JavaScript đối với các trình duyệt mới hơn này. Ai đó nên làm một số hồ sơ.


2

Đây là một trong những bài viết hay nói về eval và làm thế nào nó không phải là một tội ác: http://www.nczonline.net/blog/2013/06/25/eval-isnt-evil-just-misunder Hiểu /

Tôi không nói rằng bạn nên chạy ra ngoài và bắt đầu sử dụng eval () ở mọi nơi. Trong thực tế, có rất ít trường hợp sử dụng tốt để chạy eval () cả. Chắc chắn có những lo ngại về tính rõ ràng của mã, khả năng gỡ lỗi và hiệu năng chắc chắn không nên bỏ qua. Nhưng bạn không nên ngại sử dụng nó khi bạn gặp trường hợp eval () có ý nghĩa. Hãy thử không sử dụng nó trước, nhưng đừng để bất kỳ ai sợ bạn nghĩ rằng mã của bạn mỏng manh hơn hoặc kém an toàn hơn khi eval () được sử dụng một cách thích hợp.


2

eval () rất mạnh và có thể được sử dụng để thực thi câu lệnh JS hoặc đánh giá một biểu thức. Nhưng câu hỏi không phải là về việc sử dụng eval () mà chỉ nói một số cách chuỗi bạn chạy với eval () bị ảnh hưởng bởi một bên độc hại. Cuối cùng, bạn sẽ chạy mã độc. Với quyền lực đi kèm là trách nhiệm lớn. Vì vậy, sử dụng nó một cách khôn ngoan là bạn đang sử dụng nó. Điều này không liên quan nhiều đến hàm eval () nhưng bài viết này có thông tin khá tốt: http://bloss.popart.com/2009/07/javascript-injection-attacks/ Nếu bạn đang tìm kiếm những điều cơ bản về eval () xem tại đây: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval


2

Công cụ JavaScript có một số tối ưu hóa hiệu suất mà nó thực hiện trong giai đoạn biên dịch. Một số trong số này có thể phân tích tĩnh về mã khi nó lexes và xác định trước vị trí của tất cả các khai báo biến và hàm, do đó, sẽ mất ít nỗ lực hơn để giải quyết các định danh trong khi thực thi.

Nhưng nếu Engine tìm thấy một eval (..) trong mã, thì về cơ bản, nó phải thừa nhận rằng tất cả nhận thức về vị trí định danh của nó có thể không hợp lệ, bởi vì nó không thể biết chính xác thời gian mà bạn có thể chuyển cho eval (..) để sửa đổi phạm vi từ vựng hoặc nội dung của đối tượng bạn có thể chuyển qua để tạo phạm vi từ vựng mới cần tham khảo.

Nói cách khác, theo nghĩa bi quan, hầu hết những tối ưu hóa đó sẽ trở nên vô nghĩa nếu eval (..) có mặt, vì vậy đơn giản là nó không thực hiện tối ưu hóa.

Điều này giải thích tất cả.

Tài liệu tham khảo :

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


Không có công cụ javascript nào có thể tìm và eval trong mã với đảm bảo 100%. Do đó, nó phải sẵn sàng cho nó bất cứ lúc nào.
Jack Giffin

2

Nó không phải luôn luôn là một ý tưởng tồi. Lấy ví dụ, tạo mã. Gần đây tôi đã viết một thư viện có tên Hyperbars để thu hẹp khoảng cách giữa dom-ảotay lái . Nó làm điều này bằng cách phân tích một tay lái mẫu và chuyển đổi nó để hyperscript mà sau đó được sử dụng bởi ảo-dom. Siêu ký tự được tạo dưới dạng một chuỗi trước tiên và trước khi trả lại, eval()nó sẽ biến nó thành mã thực thi. tôi đã tìm thấyeval() trong tình huống đặc biệt này trái ngược hoàn toàn với cái ác.

Cơ bản từ

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

Để điều này

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

Hiệu suất của eval() không phải là một vấn đề trong tình huống như thế này bởi vì bạn chỉ cần diễn giải chuỗi được tạo một lần và sau đó sử dụng lại đầu ra thực thi nhiều lần.

Bạn có thể thấy cách tạo mã đã đạt được nếu bạn tò mò ở đây .


2

Tôi sẽ đi xa hơn để nói rằng nó không thực sự quan trọng nếu bạn sử dụng eval()trong javascript được chạy trong trình duyệt. * (Hãy cẩn thận)

Tất cả các trình duyệt hiện đại đều có bảng điều khiển dành cho nhà phát triển, nơi bạn có thể thực thi javascript tùy ý và bất kỳ nhà phát triển bán thông minh nào cũng có thể nhìn vào nguồn JS của bạn và đặt bất kỳ bit nào của nó vào bảng điều khiển dev để làm những gì họ muốn.

* Miễn là các điểm cuối máy chủ của bạn có xác thực & vệ sinh chính xác các giá trị do người dùng cung cấp, không có vấn đề gì được phân tích cú pháp và đánh giá trong javascript phía máy khách của bạn.

eval()Tuy nhiên, nếu bạn hỏi liệu nó có phù hợp để sử dụng trong PHP hay không, câu trả lời là KHÔNG , trừ khi bạn đưa vào danh sách trắng bất kỳ giá trị nào có thể được chuyển cho tuyên bố eval của bạn.


Không chỉ có bảng điều khiển dev, bạn cũng có thể nhập javascript: code vào thanh url để xây dựng bảng điều khiển dev của riêng bạn trên trang nếu không có, như trường hợp trên các trình duyệt IE và thiết bị di động cũ.
Dmitry

1

Tôi sẽ không cố gắng bác bỏ bất cứ điều gì đã nói ở đây, nhưng tôi sẽ đề nghị sử dụng eval () mà theo như tôi biết) không thể được thực hiện bằng bất kỳ cách nào khác. Có lẽ có nhiều cách khác để mã hóa điều này, và có thể là cách để tối ưu hóa nó, nhưng điều này được thực hiện từ lâu và không có bất kỳ tiếng chuông và tiếng huýt sáo nào để minh họa cho việc sử dụng eval mà thực sự không có bất kỳ sự thay thế nào khác. Đó là: tên đối tượng động (hoặc chính xác hơn) được tạo theo chương trình (trái ngược với giá trị).

//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: nhân tiện, tôi sẽ không đề xuất (vì tất cả các lý do bảo mật đã chỉ ra ở đây) rằng bạn căn cứ vào tên đối tượng của bạn trên đầu vào của người dùng. Tôi không thể tưởng tượng bất kỳ lý do tốt mà bạn muốn làm điều đó mặc dù. Tuy nhiên, tôi nghĩ rằng tôi sẽ chỉ ra rằng nó sẽ không phải là một ý tưởng tốt :)


3
điều này có thể được thực hiện với namespaceToTest[namespaceParts[i]], không cần eval ở đây, vì vậy sự if(typeof namespaceToTest[namespaceParts[i]] === 'undefined') { namespaceToTest[namespaceParts[i]] = {};khác biệt duy nhất choelse namespaceToTest = namespaceToTest[namespaceParts[i]];
user2144406

1

Thu gom rác thải

Bộ sưu tập rác của trình duyệt không biết liệu mã đó có thể bị xóa khỏi bộ nhớ hay không để nó được lưu trữ cho đến khi trang được tải lại. Không quá tệ nếu người dùng của bạn chỉ ở trên trang của bạn trong thời gian ngắn, nhưng nó có thể là một vấn đề đối với webapp.

Đây là một kịch bản để demo vấn đề

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

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

Một cái gì đó đơn giản như đoạn mã trên khiến một lượng nhỏ bộ nhớ được lưu trữ cho đến khi ứng dụng chết. Điều này tồi tệ hơn khi tập lệnh bị loại bỏ là một hàm khổng lồ và được gọi là khoảng thời gian.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.