Tại sao các tính năng giống như eval được coi là xấu xa, trái ngược với các tính năng có thể gây hại khác?


51

Hầu hết các ngôn ngữ hiện đại (được giải thích bằng cách nào đó) có một số loại chức năng eval . Một hàm như vậy thực thi mã ngôn ngữ tùy ý, hầu hết thời gian được dùng làm đối số chính dưới dạng một chuỗi (các ngôn ngữ khác nhau có thể thêm nhiều tính năng hơn cho hàm eval).

Tôi hiểu rằng người dùng không được phép thực thi chức năng này ( chỉnh sửa tức là lấy trực tiếp hoặc gián tiếp đầu vào tùy ý từ người dùng tùy ý để chuyển đến eval), đặc biệt là với phần mềm phía máy chủ, vì họ có thể buộc quy trình thực thi mã độc. Theo cách đó, các hướng dẫn và cộng đồng bảo chúng ta không sử dụng eval. Tuy nhiên, có nhiều lần eval hữu ích và được sử dụng:

  • Quy tắc truy cập tùy chỉnh cho các phần tử phần mềm (IIRC OpenERP có một đối tượng ir.rulecó thể sử dụng mã python động).
  • Tính toán và / hoặc tiêu chí tùy chỉnh (OpenERP có các trường như thế để cho phép tính toán mã tùy chỉnh).
  • Trình phân tích báo cáo OpenERP (vâng tôi biết tôi đang làm bạn bối rối với công cụ OpenERP ... nhưng đó là ví dụ chính tôi có).
  • Mã hóa hiệu ứng chính tả trong một số game RPG.

Vì vậy, họ có một sử dụng tốt, miễn là họ được sử dụng đúng cách. Ưu điểm chính là tính năng này cho phép quản trị viên viết mã tùy chỉnh mà không phải tạo thêm tệp và bao gồm chúng (mặc dù hầu hết các khung sử dụng tính năng eval cũng có cách chỉ định tệp, mô-đun, gói, ... để đọc từ đó).

Tuy nhiên, eval là xấu xa trong văn hóa đại chúng. Những thứ như đột nhập vào hệ thống của bạn đến với tâm trí.

Tuy nhiên, có những chức năng khác có thể gây hại nếu người dùng truy cập bằng cách nào đó: hủy liên kết, đọc, ghi (ngữ nghĩa tệp), cấp phát bộ nhớ và số học con trỏ, truy cập mô hình cơ sở dữ liệu (ngay cả khi không xem xét các trường hợp tiêm SQL).

Vì vậy, về cơ bản, hầu hết thời gian khi bất kỳnào không được viết đúng hoặc không được xem đúng cách (tài nguyên, người dùng, môi trường, ...), mã này là xấu và có thể dẫn đến tác động kinh tế.

Nhưng có một cái gì đó đặc biệt với các evalchức năng (bất kể ngôn ngữ).

Câu hỏi : Có sự thật lịch sử nào cho nỗi sợ hãi này trở thành một phần của văn hóa đại chúng, thay vì chú ý đến những đặc điểm nguy hiểm khác có thể xảy ra không?


11
Tôi không đồng ý rằng điều này quá rộng, và như một bằng chứng tôi trình bày bốn câu trả lời có độ dài hợp lý.

12
Họ bỏ phiếu đóng cửa vì quá rộng ? (Tôi chưa thể thấy phiếu bầu gần trong cộng đồng này) Lý do gần gũi đó đang trở thành lý do ký tự đại diện gần đây không có ý nghĩa gì. Đặc biệt khi điểm tôi hỏi khá rõ ràng với các ví dụ và một điểm cụ thể để hỏi. Tôi sẽ hỏi chủ đề này trong Meta ...
Luis Masuelli

13
Tại sao nó trở thành một phần của văn hóa đại chúng, với sự chú ý nhiều hơn các tính năng nguy hiểm khác? Bởi vì sự ám chỉ eval - ác rất dễ nhớ
Bergi

5
Phân bổ bộ nhớ và số học con trỏ được xem là xấu xa, bởi nhiều người.
dùng253751

5
Cần lưu ý rằng OpenERP (bây giờ là Odoo) không chỉ gọi eval, nó có một chức năng nội bộ được gọi safe_evallà chuẩn bị môi trường để ngăn chặn mã làm những việc nguy hiểm. Tuy nhiên, lỗi đã được tìm thấy vì Python là một ngôn ngữ khá linh hoạt và do đó khó kiểm soát.
André Paramés

Câu trả lời:


76

Một evalchức năng tự nó không phải là xấu, và có một điểm tinh tế mà tôi không tin rằng bạn đang thực hiện:

Cho phép một chương trình để thực thi đầu vào của người dùng tùy ý là xấu

Tôi đã viết mã sử dụng một evalloại hàm và nó được bảo mật: chương trình và tham số được mã hóa cứng. Đôi khi, không có tính năng ngôn ngữ hoặc thư viện để làm những gì chương trình cần và chạy lệnh shell là đường dẫn ngắn. "Tôi phải hoàn thành việc mã hóa này trong vài giờ, nhưng viết Java / .NET / PHP / bất kỳ mã nào sẽ mất hai ngày. Hoặc tôi có thể làm evalđiều đó trong năm phút."

Khi bạn cho phép người dùng thực thi bất cứ điều gì họ muốn, ngay cả khi bị khóa bởi đặc quyền người dùng hoặc đằng sau màn hình "an toàn", bạn sẽ tạo các vectơ tấn công. Mỗi tuần, một số CMS, phần mềm viết blog ngẫu nhiên, v.v ... có một lỗ hổng bảo mật được vá trong đó kẻ tấn công có thể khai thác lỗ hổng như thế này. Bạn đang dựa vào toàn bộ ngăn xếp phần mềm để bảo vệ quyền truy cập vào một chức năng có thể được sử dụng rm -rf /hoặc một thứ gì đó thảm khốc (lưu ý: lệnh đó không có khả năng thành công, nhưng sẽ thất bại sau khi gây ra một chút thiệt hại).

Có sự thật lịch sử nào cho nỗi sợ hãi này trở thành một phần của văn hóa đại chúng, thay vì đặt sự chú ý tương tự vào các tính năng nguy hiểm khác có thể?

Vâng, có một tiền lệ lịch sử. Do nhiều lỗi đã được sửa trong nhiều năm qua trong các phần mềm khác nhau cho phép kẻ tấn công từ xa thực thi mã tùy ý, ý tưởng về việc evalnày hầu như không được ủng hộ. Các ngôn ngữ và thư viện hiện đại có bộ chức năng phong phú khiến cho evalít quan trọng hơn và điều này không phải là ngẫu nhiên. Nó vừa làm cho các chức năng dễ sử dụng hơn vừa giảm nguy cơ khai thác.

Đã có nhiều sự chú ý đến nhiều tính năng không an toàn trong các ngôn ngữ phổ biến. Cho dù một người nhận được nhiều sự chú ý hơn chủ yếu là vấn đề quan điểm, nhưng các evaltính năng chắc chắn có một vấn đề bảo mật có thể chứng minh là dễ hiểu. Đối với một, họ cho phép thực thi các lệnh hệ điều hành bao gồm các chương trình tích hợp sẵn và các chương trình bên ngoài là tiêu chuẩn (ví dụ rmhoặc del). Hai, kết hợp với các khai thác khác, kẻ tấn công có thể tải lên tập lệnh thực thi hoặc shell của riêng chúng sau đó thực thi nó thông qua phần mềm của bạn, mở ra cánh cửa cho hầu hết mọi thứ xảy ra (không có gì tốt).

Đây là một vấn đề khó khăn. Phần mềm rất phức tạp và một ngăn xếp phần mềm (ví dụ LAMP ) là nhiều phần mềm tương tác với nhau theo những cách phức tạp. Hãy cẩn thận với cách bạn sử dụng các tính năng ngôn ngữ như thế này và không bao giờ cho phép người dùng thực thi các lệnh tùy ý.


2
Bạn là người :). Mặc dù nếu có một ví dụ nổi tiếng đã đóng góp cho nền văn hóa này, tôi muốn thấy nó trong câu trả lời.
Luis Masuelli

5
Tôi không biết về bất kỳ ví dụ đơn lẻ nào , tôi tin rằng đây là "cái chết bởi một ngàn vết cắt" với nhiều ví dụ nhỏ hơn về việc khai thác được sử dụng và vá. Tôi không phóng đại khi tôi nói rằng một số khai thác từ xa được vá hàng tuần trong một số phần mềm.

1
IDE của tôi là một chương trình cho phép tôi - đó là người dùng - thực hiện nhập liệu tùy ý. Tôi thấy nó hữu ích hơn là xấu.
Den

3
@Den đó sẽ là một ngoại lệ. Là một IDE, tôi chắc chắn bạn có thể gây ra tình trạng hỗn loạn nếu không có khả năng đó. Chỉ cần viết nó trong mã nguồn của bạn. Ngoài ra, bạn đã có toàn quyền truy cập vào máy tính mà nó chạy. Hàm ý ở đây là một đặc quyền evalcó thể nâng cao . đó không phải là một vấn đề nếu chúng đã được nâng lên.

3
@Den: Đó là những gì Raymond Chen đã tóm tắt là "phía bên kia của airlock". Bạn đã có thể chạy rm -rf /, không cần phải làm điều đó một cách phức tạp thông qua IDE. Vấn đề evallà nó mở ra khả năng đó cho rất nhiều diễn viên không nên có khả năng đó.
MSalters

38

Một phần của nó chỉ đơn giản là sắc thái là khó khăn. Thật dễ dàng để nói điều như không bao giờ sử dụng goto, trường công cộng, nội suy chuỗi cho truy vấn sql hoặc eval. Những tuyên bố này không thực sự được hiểu là nói rằng không bao giờ, trong mọi trường hợp, một lý do để sử dụng chúng. Nhưng tránh chúng như một quy tắc chung của ngón tay cái là ý tưởng tốt.

Eval rất nản lòng vì nó kết hợp một số vấn đề phổ biến.

Thứ nhất, nó dễ bị tấn công tiêm. Ở đây, nó giống như SQL tiêm ở chỗ khi dữ liệu do người dùng kiểm soát được chèn vào mã, nó dễ dàng vô tình cho phép chèn mã tùy ý.

Thứ hai, người mới bắt đầu có xu hướng sử dụng eval để đi xung quanh mã có cấu trúc xấu. Một lập trình viên mới bắt đầu có thể viết mã trông giống như:

x0 = "hello"
x1 = "world"
x2 = "how"
x3 = "are"
x4 = "you?"
for index in range(5):
   print eval("x" + index)

Điều này hoạt động, nhưng thực sự là cách sai để giải quyết vấn đề này. Rõ ràng, sử dụng một danh sách sẽ cách tốt hơn.

Thứ ba, eval thường không hiệu quả. Rất nhiều nỗ lực được dành cho việc tăng tốc triển khai ngôn ngữ lập trình của chúng tôi. Nhưng eval rất khó để tăng tốc và sử dụng nó thường sẽ có tác động bất lợi đến hiệu suất của bạn.

Vì vậy, eval không phải là xấu xa. Chúng ta có thể nói rằng eval là xấu xa, bởi vì, đó là một cách hấp dẫn để đặt nó. Bất kỳ lập trình viên mới bắt đầu nào cũng nên tránh xa eval bởi vì bất cứ điều gì họ muốn làm, eval gần như chắc chắn là giải pháp sai. Đối với các trường hợp sử dụng nâng cao nhất định, eval có ý nghĩa, và bạn nên sử dụng nó, nhưng rõ ràng hãy cẩn thận với những cạm bẫy.


13
Trường hợp thứ hai của bạn là rất quan trọng. Trong các ngôn ngữ có eval nhưng cũng được biên dịch, việc đánh giá một chuỗi để tạo ra một tham chiếu biến là không tầm thường. Ví dụ, nếu var x = 3; print(x)được biên dịch thì không cần có bất kỳ kiến ​​thức nào về thời gian chạy mà nguồn sử dụng tên "x". Để var x = 3; print(eval("x"))làm việc, ánh xạ đó cần phải được ghi lại. Đây là một vấn đề thực sự: trong Common Lisp (let ((x 3)) (print (eval 'x)))sẽ đưa ra một ngoại lệ biến không liên kết vì biến từ vựng x không có bất kỳ kết nối nào với tên sau khi mã được biên dịch.
Joshua Taylor

@JohnuaTaylor Ý bạn là lý do thứ ba chứ không phải thứ hai?
dùng253751

1
@immibis, tôi nghĩ rằng anh ấy đang đề cập đến mã trong lý do thứ hai. Nhưng bạn đã đúng, nó thực sự liên quan đến lý do thứ ba: hiệu suất.
Winston Ewert

Thấy câu hỏi này phải không? ;)
jpmc26 ngày

@ jpmc26, không. Nhưng tôi đã thấy rất nhiều như thế.
Winston Ewert ngày

20

Điều nó sôi nổi là "thực thi mã tùy ý" là công nghệ nói về "có thể làm bất cứ điều gì." Nếu ai đó có thể khai thác việc thực thi mã tùy ý trong mã của bạn, đây thực sự là lỗ hổng bảo mật tồi tệ nhất có thể, bởi vì điều đó có nghĩa là họ có thể làm bất cứ điều gì có thể để hệ thống của bạn làm.

"Các lỗi có thể có hại khác" có thể có các giới hạn, có nghĩa là, theo định nghĩa, chúng có khả năng gây hại ít hơn so với việc thực thi mã tùy ý đang bị khai thác.


2
Để tranh luận, việc sử dụng sai các con trỏ cũng dẫn đến việc thực thi mã tùy ý , nhưng các con trỏ được tán thành ít hơn nhiều so với eval.
Dmitry Grigoryev

12
@DmitryGrigoryev Họ có thật không? Bên ngoài C ++, con trỏ thường được coi là cực kỳ nguy hiểm và tránh được. C # hỗ trợ con trỏ, ví dụ, nhưng nó có xu hướng là điều cuối cùng bạn thử sau khi bạn sử dụng hết tất cả các tùy chọn khác (thông thường, vì lý do hiệu suất về thao tác dữ liệu). Hầu hết các ngôn ngữ hiện đại không có hỗ trợ cho con trỏ. Ngay cả bản thân C ++ cũng đang hướng tới các con trỏ "an toàn hơn", cố gắng giảm bớt các vấn đề với các con trỏ tùy ý (ví dụ: sử dụng danh sách / mảng thực sự thay vì chỉ con trỏ, sử dụng safe_ptr, chuyển tham chiếu ...).
Luaan

2
@DmitryGrigoryev: Bạn có thể cung cấp tài liệu tham khảo cho bất kỳ ai nói rằng con trỏ ít nguy hiểm hơn eval không?
JacquesB


1
@JacquesB, vâng; nó được dự định như một trò đùa (tôi mong nụ cười sẽ làm cho nó đủ rõ ràng). OP đã đưa ra tuyên bố đó, không phải tôi, vì vậy bạn nên yêu cầu anh ta chứng minh.
Dmitry Grigoryev

15

Có một lý do thực tế và lý thuyết.

Lý do thực tế là chúng tôi quan sát nó thường xuyên gây ra vấn đề. Thật hiếm khi eval dẫn đến một giải pháp tốt, và nó thường dẫn đến giải pháp tồi tệ khi cuối cùng bạn đã có một giải pháp tốt hơn nếu bạn giả vờ eval không tồn tại và tiếp cận vấn đề khác đi. Vì vậy, lời khuyên đơn giản là bỏ qua nó, và nếu bạn đưa ra một trường hợp bạn muốn bỏ qua lời khuyên đơn giản hóa, hãy hy vọng bạn đã nghĩ đủ để hiểu tại sao lời khuyên đơn giản hóa không áp dụng và phổ biến cạm bẫy sẽ không ảnh hưởng đến bạn.

Lý do lý thuyết hơn là nếu khó viết mã tốt, viết viết tốt còn khó hơn . Cho dù bạn đang sử dụng eval hoặc tạo các câu lệnh SQL bằng cách gắn các chuỗi hoặc viết trình biên dịch JIT, những gì bạn đang cố gắng thường khó hơn bạn mong đợi. Tiềm năng tiêm mã độc là một phần lớn của vấn đề, nhưng bên cạnh đó, nói chung khó biết mã của bạn là chính xác nếu mã của bạn thậm chí không tồn tại cho đến khi chạy. Vì vậy, lời khuyên đơn giản là giữ cho mọi thứ dễ dàng hơn cho chính bạn: "sử dụng các truy vấn SQL được tham số hóa", "không sử dụng eval".

Lấy ví dụ về hiệu ứng chính tả của bạn: đó là một điều để xây dựng trình biên dịch hoặc trình thông dịch Lua (hoặc bất cứ thứ gì) vào trò chơi của bạn để cho phép các nhà thiết kế trò chơi một ngôn ngữ dễ dàng hơn C ++ (hoặc bất cứ điều gì) để mô tả hiệu ứng chính tả. Hầu hết các "vấn đề của eval" không áp dụng nếu tất cả những gì bạn đang làm là đánh giá mã đã được viết và kiểm tra và đưa vào trò chơi hoặc trong DLC ​​hoặc những gì bạn có. Đó chỉ là sự pha trộn ngôn ngữ. Các vấn đề lớn xảy ra với bạn khi bạn cố gắng tạo Lua (hoặc C ++, hoặc SQL hoặc các lệnh shell hoặc bất cứ điều gì) một cách nhanh chóng và làm rối tung nó.


1
Tất nhiên, việc tạo mã thời gian chạy có thể được thực hiện chính xác và eval thể hữu ích. Ví dụ: tôi thường xuyên sử dụng eval cho các công cụ siêu lập trình / macro, đặc biệt là khi tôi muốn có hiệu suất cao hơn một trình dọn dẹp OOP hay một giải pháp chức năng có thể cung cấp. Mã kết quả thường tốt hơn và đơn giản hơn vì có ít mẫu mã hơn. Tuy nhiên, nhận thức được các vấn đề khác nhau liên quan đến hộp cát, cơ chế thoát hiểm, tiêm mã, quy tắc phạm vi, báo cáo lỗi, tối ưu hóa, v.v ... đòi hỏi mức độ thành thạo ngôn ngữ không cần thiết và eval rất nguy hiểm nếu không có kiến ​​thức đó.
amon

11

Không, không có sự thật lịch sử rõ ràng.

Các tệ nạn của eval là đơn giản để xem từ đầu. Các tính năng khác là nguy hiểm nhẹ. Mọi người có thể xóa dữ liệu. Mọi người có thể thấy dữ liệu họ không nên. Mọi người có thể viết dữ liệu họ không nên. Và họ chỉ có thể làm hầu hết những điều đó nếu bạn bằng cách nào đó làm hỏng và không xác thực đầu vào của người dùng.

Với eval, họ có thể hack hình ngũ giác và làm cho nó trông giống như bạn đã làm. Họ có thể kiểm tra tổ hợp phím của bạn để lấy mật khẩu của bạn. Giả sử một ngôn ngữ hoàn chỉnh Turing, họ thực sự có thể làm bất cứ điều gì máy tính của bạn có khả năng làm.

Và bạn không thể xác nhận đầu vào. Đó là một chuỗi biểu mẫu miễn phí tùy ý. Cách duy nhất để xác nhận nó là xây dựng một trình phân tích cú pháp và phân tích mã cho ngôn ngữ được đề cập. Tốt nhất của may mắn với điều đó.


1
... hoặc có đầu vào đến từ một nguồn đáng tin cậy, chẳng hạn như các tệp định nghĩa chính tả cho trò chơi.
dùng253751

3
@immibis nhưng nếu đầu vào được xác định trước và được kiểm tra an toàn thì tại sao lại sử dụng eval khi nó có thể được đưa vào nguồn của hệ thống?
Jules

3
@immibis - bởi vì không ai từng hack các tệp trò chơi ...
Telastyn

2
... Đó không phải là "Turing hoàn thành" nghĩa là gì (Tính đầy đủ của Turing là một bước so với không liên quan đến điện toán trong thế giới thực).
Leushenko

1
@Telastyn: Điều mà một chương trình Javascript không thể làm được. Hoặc thậm chí là một chương trình C ++. Javascript chạy bên trong một hộp cát (trình duyệt) mà chính nó nằm trong một hộp cát khác (vòng 3 trong x86 nói). Vectơ ngắt nằm ngoài hộp cát đó, dưới sự kiểm soát của hệ điều hành. Và hộp cát ngoài đó, vòng 3, được thi hành bởi CPU.
MSalters

6

Tôi nghĩ rằng nó nắm rõ các khía cạnh sau đây:

  • Sự cần thiết
  • (Được bảo vệ) Cách sử dụng
  • Truy cập
  • Kiểm chứng
  • Tấn công nhiều giai đoạn

Sự cần thiết

Xin chào, tôi đã viết công cụ chỉnh sửa hình ảnh cực kỳ thú vị này (có sẵn với giá 0,02 đô la). Sau khi bạn đã mở hình ảnh, bạn có thể vượt qua vô số bộ lọc trên hình ảnh của mình. Thậm chí, bạn có thể tự viết kịch bản bằng Python (chương trình tôi đã viết ứng dụng). Tôi sẽ chỉ sử dụng evalđầu vào của bạn, tin tưởng bạn là người dùng đáng kính.

(một lát sau)

Cảm ơn đã mua nó. Như bạn có thể thấy nó hoạt động chính xác như tôi đã hứa. Oh, bạn muốn mở một hình ảnh? Không, bạn không thể. Tôi sẽ không sử dụng readphương pháp này vì nó không an toàn. Tiết kiệm? Không, tôi sẽ không sử dụng write.

Điều tôi đang cố gắng nói là: Bạn cần đọc / viết cho hầu hết các công cụ cơ bản. Tương tự cho việc lưu trữ điểm số cao của trò chơi oh-so-awesome của bạn.

Không đọc / ghi, trình chỉnh sửa hình ảnh của bạn là vô dụng. Không có eval? Tôi sẽ viết cho bạn một plugin tùy chỉnh cho điều đó!

(Được bảo vệ) Cách sử dụng

Rất nhiều phương pháp có thể có khả năng gây nguy hiểm. Giống như, ví dụ readwrite. Một ví dụ phổ biến là một dịch vụ web cho phép bạn đọc hình ảnh từ một thư mục cụ thể bằng cách chỉ định tên. Tuy nhiên, trên thực tế, 'tên' có thể là bất kỳ đường dẫn (tương đối) hợp lệ nào trên hệ thống, cho phép bạn đọc tất cả các tệp mà dịch vụ web có quyền truy cập, không chỉ là hình ảnh. Lạm dụng ví dụ đơn giản này được gọi là 'đường truyền'. Nếu ứng dụng của bạn cho phép truyền tải đường dẫn, điều đó thật tệ. A readmà không bảo vệ chống lại con đường xuyên qua có thể được gọi là ác.

Tuy nhiên, trong các trường hợp khác, chuỗi for readhoàn toàn nằm dưới sự kiểm soát của lập trình viên (có thể được mã hóa cứng?). Trong trường hợp đó, nó khó sử dụng read.

Truy cập

Bây giờ, một ví dụ đơn giản khác, sử dụng eval.

Ở đâu đó trong ứng dụng web của bạn, bạn muốn một số nội dung động. Bạn sẽ cho phép quản trị viên nhập một số mã có thể thực thi được. Xem như quản trị viên là người dùng đáng tin cậy, về mặt lý thuyết có thể ổn. Chỉ cần đảm bảo không thực thi mã được gửi bởi người không phải quản trị viên và bạn sẽ ổn.

(Đó là, cho đến khi bạn sa thải quản trị viên tốt bụng đó nhưng quên thu hồi quyền truy cập của anh ta. Bây giờ ứng dụng web của bạn đã bị hỏng).

Kiểm chứng.

Một khía cạnh quan trọng khác, tôi nghĩ, là việc xác minh đầu vào của người dùng dễ dàng như thế nào.

Sử dụng đầu vào của người dùng trong một cuộc gọi đọc? Chỉ cần đảm bảo (rất) chắc chắn rằng đầu vào cho cuộc gọi đọc không chứa bất cứ thứ gì độc hại. Bình thường hóa đường dẫn và xác minh tệp được mở trong thư mục phương tiện của bạn. Bây giờ thì an toàn.

Người dùng nhập vào một cuộc gọi viết? Tương tự!

SQL tiêm? Chỉ cần thoát nó hoặc sử dụng các truy vấn tham số và bạn đã an toàn.

Eval? Làm thế nào bạn sẽ xác minh đầu vào được sử dụng cho evalcuộc gọi? Bạn có thể làm việc rất chăm chỉ, nhưng thực sự rất khó (nếu không nói là không thể) để làm cho nó hoạt động an toàn.

Tấn công nhiều giai đoạn

Bây giờ, mỗi khi bạn sử dụng đầu vào của người dùng, bạn cần cân nhắc lợi ích của việc sử dụng nó, chống lại những nguy hiểm. Bảo vệ việc sử dụng nó càng nhiều càng tốt.

Xem xét lại các evalcông cụ có thể trong ví dụ quản trị viên. Tôi nói với bạn rằng đó là loại ok.

Bây giờ, hãy xem xét rằng thực sự có một vị trí trong ứng dụng web của bạn mà bạn quên thoát nội dung người dùng (HTML, XSS). Đó là một hành vi phạm tội ít hơn so với eval người dùng có thể truy cập. Nhưng, bằng cách sử dụng nội dung người dùng không được giải thoát, người dùng có thể chiếm quyền duyệt trình duyệt web của quản trị viên và thêm một evalblob có thể thông qua phiên quản trị viên, cho phép truy cập lại toàn bộ hệ thống.

(Tấn công nhiều giai đoạn tương tự có thể được thực hiện với SQL tiêm thay vì XSS hoặc một số tệp tùy ý ghi thay thế mã thực thi thay vì sử dụng eval)


2
"Bạn có thể làm việc rất chăm chỉ, nhưng thực sự rất khó (nếu không thể) để làm cho nó hoạt động an toàn." - Đó điều không thể. Bằng chứng đơn giản: thay vì cố gắng tìm hiểu xem mã mà người dùng cung cấp có "an toàn" hay không, chỉ cần thử tìm ra thứ gì đó đơn giản hơn nhiều, và xem nó đã khó đến mức nào : mã do người dùng cung cấp có dừng lại không?
Jörg W Mittag

2
@ JörgWMittag: cho tôi một chương trình được viết bằng Coq và tôi sẽ chứng minh điều đó.
André Paramés

1
@ JörgWMittag: Đồng ý. Tùy thuộc vào ngôn ngữ và phạm vi đầu vào của người dùng. Nó cũng có thể được eval("hard coded string" + user_input_which_should_be_alphanumeric + "remainder"). Xác minh rằng đầu vào là chữ và số là có thể. Ngoài ra, 'nó dừng lại' là trực giao với 'nó có sửa đổi / truy cập trạng thái mà nó không nên chạm vào không' và 'nó có phương thức cal không nên gọi'.
Sjoerd Job Postmus

3
@ JörgWMittag Không thể chứng minh rằng một chương trình nhất định sẽ không làm gì đó, nhưng không thể xác định một cách bảo thủ một bộ chương trình bị hạn chế mà bạn có thể chứng minh và thực thi rằng các chương trình đầu vào là thành viên của bộ đó.
dùng253751 ngày

3

Để tính năng này hoạt động hoàn toàn, điều đó có nghĩa là tôi cần giữ một lớp phản chiếu xung quanh cho phép truy cập đầy đủ vào toàn bộ trạng thái bên trong của chương trình.

Đối với các ngôn ngữ thông dịch, tôi chỉ có thể sử dụng trạng thái trình thông dịch, điều này rất dễ, nhưng kết hợp với trình biên dịch JIT, nó vẫn làm tăng đáng kể độ phức tạp.

Nếu không eval, trình biên dịch JIT thường có thể chứng minh rằng dữ liệu cục bộ của một luồng không được truy cập từ bất kỳ mã nào khác, do đó, hoàn toàn có thể chấp nhận để sắp xếp lại các truy cập, bỏ qua các khóa và lưu trữ dữ liệu thường được sử dụng trong thời gian dài hơn. Khi một luồng khác thực thi một evalcâu lệnh, có thể cần phải đồng bộ hóa mã được biên dịch JIT đang chạy với điều đó, vì vậy đột nhiên mã được tạo ra JIT cần một cơ chế dự phòng quay trở lại thực thi không tối ưu hóa trong khung thời gian hợp lý.

Loại mã này có xu hướng có rất nhiều lỗi tinh vi, khó tái tạo và đồng thời nó cũng đặt ra giới hạn tối ưu hóa trong trình biên dịch JIT.

Đối với các ngôn ngữ được biên dịch, sự đánh đổi thậm chí còn tồi tệ hơn: Hầu hết các tối ưu hóa đều bị cấm và tôi cần giữ thông tin biểu tượng rộng rãi và một thông dịch viên, vì vậy tính linh hoạt bổ sung thường không đáng giá - thường dễ dàng hơn để xác định giao diện với một số nội bộ cấu trúc, ví dụ bằng cách đưa ra một khung nhìn kịch bản và bộ điều khiển truy cập đồng thời vào mô hình của chương trình .


"Để tính năng này hoạt động hoàn toàn, điều đó có nghĩa là tôi cần giữ một lớp phản chiếu xung quanh cho phép truy cập đầy đủ vào toàn bộ trạng thái bên trong của chương trình" - không, chỉ với các phần bạn muốn tác động. Trong trường hợp OpenERP / Odoo, mã được đánh giá chỉ có quyền truy cập vào một số lượng biến và hàm rất hạn chế mà nó có thể gọi và chúng đều là luồng cục bộ.
André Paramés

1

Tôi từ chối tiền đề evalđược coi là xấu xa hơn số học con trỏ hoặc nguy hiểm hơn truy cập hệ thống tập tin và bộ nhớ trực tiếp. Tôi không biết bất kỳ nhà phát triển hợp lý nào sẽ tin vào điều đó. Hơn nữa, các ngôn ngữ hỗ trợ truy cập số học / bộ nhớ trực tiếp thường không hỗ trợ evalvà ngược lại, vì vậy tôi lưu ý rằng tần suất so sánh như vậy thậm chí có liên quan.

Nhưng evalcó thể là một lỗ hổng được biết đến nhiều hơn , vì lý do đơn giản là nó được JavaScript hỗ trợ. JavaScript là ngôn ngữ được hộp cát không có bộ nhớ trực tiếp hoặc truy cập hệ thống tệp, do đó, đơn giản là nó không có các lỗ hổng này để ngăn chặn các điểm yếu trong chính việc triển khai ngôn ngữ. Evaldo đó là một trong những tính năng nguy hiểm nhất của ngôn ngữ, vì nó mở ra khả năng thực thi mã tùy ý. Tôi tin rằng nhiều nhà phát triển phát triển bằng JavaScript hơn trong C / C ++, vì vậy, điều evalquan trọng hơn là phải nhận thức được hơn là tràn bộ đệm cho phần lớn các nhà phát triển.


0

Không có lập trình viên nghiêm túc nào coi Eval là "Ác quỷ". Nó chỉ đơn giản là một công cụ lập trình, giống như bất kỳ công cụ nào khác. Sự sợ hãi (nếu có một nỗi sợ) của chức năng này không liên quan gì đến văn hóa đại chúng. Nó chỉ đơn giản là một lệnh nguy hiểm thường được sử dụng sai và có thể gây ra các lỗ hổng bảo mật nghiêm trọng và làm giảm hiệu suất. Từ kinh nghiệm của bản thân, tôi sẽ nói rằng rất hiếm khi gặp phải sự cố lập trình mà không thể giải quyết an toàn và hiệu quả hơn bằng một số phương tiện khác. Các lập trình viên có khả năng sử dụng eval nhiều nhất, là những người có lẽ ít có trình độ nhất để làm điều đó một cách an toàn.

Phải nói rằng, có những ngôn ngữ mà việc sử dụng eval là phù hợp. Perl đến với tâm trí. Tuy nhiên, cá nhân tôi thấy nó rất hiếm khi cần trong các ngôn ngữ khác, hiện đại hơn, vốn hỗ trợ xử lý ngoại lệ có cấu trúc.


điều này thậm chí không cố gắng giải quyết câu hỏi được hỏi, "Có sự thật lịch sử nào cho nỗi sợ hãi này trở thành một phần của văn hóa đại chúng không". Xem cách trả lời
gnat

Câu hỏi, theo tôi, dựa trên một tiền đề sai, vì vậy tôi đã trả lời nó như vậy.
dùng1751825 ngày

0

Tôi nghĩ rằng bạn bao quát nó khá tốt trong phần sau của câu hỏi của bạn (nhấn mạnh của tôi):

chúng có công dụng tốt, miễn là chúng được sử dụng đúng cách

Đối với 95% những người có thể sử dụng nó đúng cách, tất cả đều tốt và tốt; nhưng sẽ luôn có những người không sử dụng nó đúng cách. Một số trong số đó sẽ xuống thiếu kinh nghiệm và thiếu khả năng, phần còn lại sẽ độc hại.

Sẽ luôn có những người muốn đẩy ranh giới và tìm lỗ hổng bảo mật - một số tốt, một số xấu.

Đối với khía cạnh thực tế lịch sử của nó, các evalhàm kiểu về cơ bản cho phép thực thi mã tùy ý đã được khai thác trước đây trong CMS web phổ biến, Joomla! . Với Joomla! cung cấp năng lượng cho hơn 2,5 triệu trang web trên toàn thế giới , đó là rất nhiều thiệt hại tiềm ẩn không chỉ đối với khách truy cập vào các trang web đó, mà còn có khả năng đối với cơ sở hạ tầng được lưu trữ trên đó và cả danh tiếng của các trang web / công ty đã bị khai thác.

Joomla! ví dụ có thể là một cái đơn giản, nhưng nó là một cái đã được ghi lại.


0

Có một số lý do chính đáng để không khuyến khích việc sử dụng eval(mặc dù một số lý do cụ thể đối với một số ngôn ngữ nhất định).

  • Môi trường (từ vựng và động) được sử dụng evalthường xuyên gây ngạc nhiên (nghĩa là bạn nghĩ eval(something here)nên làm một việc, nhưng nó làm một việc khác, có thể gây ra ngoại lệ)
  • Thường có một cách tốt hơn để hoàn thành điều tương tự (nối các từ khóa được xây dựng đôi khi là một giải pháp tốt hơn, nhưng đó cũng có thể là đặc thù chung của Lisp)
  • Thật quá dễ dàng để kết thúc với dữ liệu không an toàn được đánh giá (mặc dù điều này chủ yếu có thể được bảo vệ chống lại).

Cá nhân tôi sẽ không đi xa như nói rằng điều đó là xấu xa, nhưng tôi sẽ luôn thách thức việc sử dụng evaltrong đánh giá mã, với dòng chữ "bạn đã xem xét một số mã ở đây chưa?" (nếu tôi có thời gian để thực hiện ít nhất một sự thay thế dự kiến), hoặc "bạn có chắc chắn một eval thực sự là giải pháp tốt nhất ở đây?" (nếu tôi không).


điều này thậm chí không cố gắng giải quyết câu hỏi được hỏi, "Có sự thật lịch sử nào cho nỗi sợ hãi này trở thành một phần của văn hóa đại chúng không". Xem cách trả lời
gnat

0

Trong Hiệp hội Tâm trí của Minsky , Chương 6.4, ông nói

một cách để một tâm trí tự quan sát và vẫn theo dõi những gì đang xảy ra. Chia bộ não thành hai phần, A và B. Kết nối đầu vào và đầu ra của bộ não A với thế giới thực - để nó có thể cảm nhận được những gì xảy ra ở đó. Nhưng đừng kết nối não B với thế giới bên ngoài; thay vào đó hãy kết nối nó để bộ não A là thế giới của bộ não B!

Khi một chương trình (B) viết một chương trình khác (A), nó hoạt động như một chương trình meta. Đối tượng của B là chương trình A.

Có chương trình C. Đó là cái trong đầu bạn viết chương trình B.

Điều nguy hiểm là có thể có ai đó (C ') với mục đích xấu, người có thể can thiệp vào quá trình này, vì vậy bạn có được những thứ như SQL-tiêm.

Thách thức là làm cho phần mềm thông minh hơn mà không làm cho nó nguy hiểm hơn.


Hai upvote, và hai downvote. Có vẻ như điều này có thể đánh vào một dây thần kinh.
Mike Dunlavey

0

Bạn có rất nhiều câu trả lời hay ở đây và lý do chính rõ ràng là việc thực thi mã tùy ý là mmmkay xấu nhưng tôi sẽ thêm một yếu tố khác mà những người khác chỉ chạm vào:

Thật sự rất khó để khắc phục sự cố mã đang được đánh giá ra khỏi chuỗi văn bản. Các công cụ sửa lỗi thông thường của bạn nằm khá gần cửa sổ và bạn bị giảm xuống theo dấu vết hoặc trường học rất cũ. Rõ ràng điều đó không quan trọng lắm nếu bạn có một đoạn trong một lớp lót mà bạn muốn evalnhưng với tư cách là một lập trình viên có kinh nghiệm, bạn có thể tìm thấy một giải pháp tốt hơn cho điều đó, trong khi việc tạo mã quy mô lớn hơn có thể là một chức năng đánh giá trở thành một đồng minh có khả năng hữu ích.

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.