Cái gì cấu thành nên sử dụng không đúng cách của tính năng Eval javascript? [đóng cửa]


13

Eval là một tính năng ngôn ngữ gây tranh cãi nổi tiếng. Douglas Crockford thẳng thừng từ chối nó. Tôi đang tự hỏi những rủi ro cụ thể mà Eval mang lại. Theo câu hỏi này ,Improper use of eval opens up your code for injection attacks ,.

Một số cách sử dụng không đúng của lệnh Eval là gì và chúng mở ra những lỗ hổng bảo mật nào?

Câu trả lời:


31

Quay lại khi tôi đang triển khai công cụ JScript, tôi đã ủng hộ việc có những chiếc áo EVAL IS EVIL được in lên nhưng thật đáng buồn là chúng tôi không bao giờ có được nó.

Vấn đề lớn nhất của tôi với eval không phải là cuộc tấn công tiêm mã độc rõ ràng, mặc dù điều đó chắc chắn là mối quan tâm lớn. Vấn đề lớn nhất của tôi với nó là mọi người có xu hướng sử dụng nó như một cái búa thực sự lớn để giải quyết những vấn đề thực sự nhỏ. Hầu hết các cách sử dụng trong thế giới thực mà tôi thấy về "eval" trong tự nhiên khi tôi ở trong nhóm JScript có thể đã được giải quyết một cách tầm thường bằng cách sử dụng bảng tra cứu; và vì mọi đối tượng trong JScript đã là một bảng tra cứu nên nó không giống như đó là một gánh nặng quá lớn. Eval khởi động lại trình biên dịchphá hủy hoàn toàn khả năng của trình biên dịch để tối ưu hóa mã của bạn .

Để biết thêm một số suy nghĩ trong tĩnh mạch này, xem các bài viết của tôi từ năm 2003 về chủ đề này:

Tội ác chung:

http://bloss.msdn.com/b/ericlippert/archive/2003/11/01/53329.aspx

Tội ác tấn công:

http://bloss.msdn.com/b/ericlippert/archive/2003/11/04/53335.aspx


Bạn nghĩ gì về việc sử dụng evalcác đoạn mã lớn theo cách mà các ứng dụng như JSPacker thích? JSPacker + gzip thường dẫn đến kích thước tệp nhỏ hơn so với giải pháp của riêng nó, nhưng như bạn chỉ ra một cách chính xác, về cơ bản, nó sẽ kích hoạt trình biên dịch hai lần trên cùng một đoạn mã, cộng với một số chi phí thay thế chuỗi.
Matthew Scharley

2
@Matthew: Thường có sự đánh đổi giữa không gian và thời gian, và tận dụng lợi thế của sự đánh đổi đó đôi khi có thể là một chiến thắng lớn. Nếu mục đích của kỹ thuật là cải thiện hiệu suất thì ý kiến ​​của tôi là nếu đo lường cẩn thận cho thấy đó là một chiến thắng đáng kể trong các kịch bản thực tế mà không đưa ra các lỗ hổng bảo mật, thật tuyệt, hãy làm điều đó. Nhưng tôi không biết đủ về kỹ thuật cụ thể để chỉ trích các chi tiết của nó.
Eric Lippert

Tôi muốn một trong những câu trả lời tôi đã nhìn thấy một trong hai ở đây hoặc trên SO bản thân sẽ nói những gì các quốc gia liên kết thứ hai của mình: đó eval()không một nguy cơ bảo mật trên máy khách (trình duyệt) mã.
sq33G

4

Hầu hết các lỗ hổng bảo mật là cùng một loại lỗ hổng như với SQL tiêm, cụ thể là nối dữ liệu người dùng vào mã JavaScript. Sự khác biệt là trong khi có nhiều cách để đảm bảo điều này không xảy ra với SQL, thì bạn không thể làm gì nhiều với JavaScript.

Là một ví dụ tầm thường và vô dụng, một máy tính JavaScript đơn giản:

textbox1.value = eval(textbox2.value);

Một ví dụ sử dụng đúng là một số trình đóng gói JavaScript nén JavaScript bằng cách lấy ra các từ phổ biến và thay thế chúng bằng các thay thế 1-2 ký tự ngắn. Trình đóng gói sau đó xuất tất cả điều này cùng với mã thay thế chuỗi dựa trên từ điển được tạo sau đó làm mất kết quả.


1

Có một số điều không thể thực hiện trong JS nếu không có hàm giống như eval ( eval,Function và có thể nhiều hơn).

Lấy applyví dụ. Nó rất dễ sử dụng khi sử dụng nó trong các cuộc gọi chức năng thông thường:

foo.apply(null, [a, b, c])

Nhưng làm thế nào bạn sẽ làm điều này cho các đối tượng bạn đang tạo thông qua cú pháp mới?

new Foo.apply(null, [a, b, c]) không hoạt động, cũng không làm các hình thức tương tự.

Nhưng bạn có thể giải quyết giới hạn này thông qua evalhoặc Function(tôi sử dụng Functiontrong ví dụ này):

Function.prototype.New = (function () {
    var fs = [];
    return function () {
        var f = fs[arguments.length];
        if (f) {
            return f.apply(this, arguments);
        }
        var argStrs = [];
        for (var i = 0; i < arguments.length; ++i) {
            argStrs.push("a[" + i + "]");
        }
        f = new Function("var a=arguments;return new this(" + argStrs.join() + ");");
        if (arguments.length < 100) {
            fs[arguments.length] = f;
        }
        return f.apply(this, arguments);
    };
}) ();

Thí dụ:

Foo.New.apply(null, [a, b, c]);

Tất nhiên, bạn có thể tự xây dựng các hàm Function.prototype.Newsử dụng, nhưng không chỉ dài dòng và cồng kềnh này, nó (theo định nghĩa) phải là hữu hạn. Functioncho phép mã làm việc cho bất kỳ số lượng đối số.


2
Đúng, nhưng câu hỏi của OP là " Một số cách sử dụng lệnh Eval không phù hợp và chúng mở ra những lỗ hổng bảo mật nào? ", Chứ không phải là "Cách sử dụng tốt eval()? "
Ross Patterson

1
@RossPatterson: Đoán tôi chủ yếu nhìn vào tiêu đề của câu hỏi haha.
Thomas Eding

Tuy nhiên, +1 để tìm cách sử dụng tốt cho tính năng ngôn ngữ xấu :-)
Ross Patterson

1

Một phần câu trả lời trực tiếp từ phía tôi là phát triển khu vực thử nghiệm API hướng nhà phát triển. Chúng tôi đã đưa ra một vùng văn bản trên một trang và nút Run. Điểm chính của trang là để họ có thể thử mọi thứ trong Javascript dựa trên API giao tiếp iframe của chúng tôi, điều không dễ thực hiện trong môi trường cục bộ.

Bất cứ điều gì độc hại có thể được thực hiện trong trường hợp đó cũng có thể được thực hiện bởi nhà phát triển mở công cụ F12 của họ.


0

Tôi đồng ý rằng nó rất hiếm khi được sử dụng, nhưng tôi đã tìm thấy một trường hợp sử dụng mạnh mẽ cho eval .

Có một tính năng mới thử nghiệm trong Firefox có tên là asm.js tôi đã làm việc với. Nó cho phép một tập hợp con giới hạn của ngôn ngữ Javascript được biên dịch thành mã gốc. Vâng, điều này là rất tuyệt vời, nhưng nó có những hạn chế. Bạn có thể nghĩ tập hợp con giới hạn của Javascript là ngôn ngữ giống như C được nhúng trong Javascript. Nó không thực sự có nghĩa là được đọc hoặc viết bởi con người.

Tập hợp con giới hạn này của Javascript không cho phép tôi đưa mã được tạo trong thời gian chạy vào mã được biên dịch sau khi được biên dịch.

Tôi đã viết một số mã cho phép người dùng viết, theo ký hiệu quen thuộc, một biểu thức toán học và chuyển nó thành mã asm.js. Trừ khi tôi muốn mã được xử lý ở phía máy chủ (mà tôi không có), evallà công cụ duy nhất cho phép tôi xử lý mã kết quả do trình duyệt xử lý trong thời gian thực.


0

Như những người khác đã chỉ ra, điều quan trọng nhất khi làm việc với evalnó là giữ an toàn. Vì vậy, bạn muốn kiểm tra đối số kỹ lưỡng và giữeval mã ed đơn giản vì thường khó bảo trì và bảo mật mã được tạo trong thời gian chạy.

Điều đó đang được nói, tôi thích sử dụng evalcho hai loại điều (mặc dù có thể có những lựa chọn tốt hơn, ít ác hơn):

  1. evallà một cách "mã bộ nhớ đệm rõ ràng", nên nó có thể được sử dụng để cải thiện hiệu suất. Lưu ý rằng tối ưu hóa luôn được cải thiện, nhưng đơn giản là không có gì đảm bảo về những gì họ có thể làm cho bạn. Bằng cách làm cho mọi thứ rõ ràng trong mã, bạn thực sự có thể giúp trình tối ưu hóa đưa ra quyết định thông minh hơn.
  2. Nó cũng có thể được sử dụng để cung cấp các hình thức cơ bản về an toàn kiểu, cũng như các tính năng ngôn ngữ khác mà JS đang thiếu, mà không làm giảm hiệu suất.

Ví dụ, cách tiếp cận trình lặp đối tượng được biên dịch trước này , cho thấy các lợi ích hiệu năng rõ ràng khi sử dụng evalcho phép lặp thuộc tính đối tượng. Nó cũng cho thấy sự khởi đầu của một hệ thống loại mạnh mẽ có thể cung cấp kiểm tra ràng buộc ngầm và nhiều hơn nữa, với chi phí thấp.

Nhiều nhà phát triển Javascript dày dạn có lẽ sẽ chỉ ra rằng đây là một lỗ thỏ, vì, nếu bạn bắt đầu viết Javascript theo cách này, về cơ bản bạn sẽ thay đổi cách bạn sử dụng ngôn ngữ. Tuy nhiên, điều đó có thể không nhất thiết là điều tồi tệ đối với những người thích Javascript nhưng cũng thiếu các tính năng ngôn ngữ cơ bản chỉ có thể đạt được bằng cách thay đổi cách chúng ta sử dụng ngôn ngữ.


-3

Tôi có một tình huống trong đó eval trông giống như cách để đi, đánh giá một chuỗi và trả về một biến hiện có tên giống với chuỗi.

Tôi có một số bảng: table1ResultsTable, table2ResultsTable, tableNResultsTable. Tôi có các biến được thiết lập với cùng tên, đó là các đối tượng có thể truy cập được jQuery. Tôi sử dụng chúng để thiết lập các bảng và gọi các hàm có thể truy xuất jQuery trên chúng.

Mỗi bảng có class = "resultsTable" được gán. Bây giờ, tôi cần lấy biến khi bảng được nhấp. Tôi đang làm điều này:

$('resultsTable).on('click', 'td', function(event) {
    var cResultsTable = eval(event.target.parentElement.parentElement.parentElement.id);
    [etc]
});

Vì vậy, tôi nhận được id của bảng trong đó ô được nhấp vào, có cùng tên với biến đối tượng có thể truy cập tương ứng với nó. Nếu ai đó có một đề nghị cải tiến tôi muốn biết về nó.


1
Tại sao bạn cần eval? Id phải là một chuỗi đơn giản, không phải là mã. Nhưng dù sao, event.target.parentElement.parentElement.parentElementlà khủng khiếp. Hơn nữa, tôi mong muốn cuộc gọi eval tạo ra lỗi "lỗi tham chiếu: [id] không được xác định", trừ khi bạn cố tình sử dụng id có thể đánh giá được (bị hỏng, sai và có thể gây ra những điều kỳ lạ xảy ra nếu bạn kết thúc tạo id trùng lặp).
Brian

Có lẽ tôi không làm cho mình rõ ràng. Id là một chuỗi đơn giản. Đó là id của bảng đã được nhấp. Tôi cũng có một biến đối tượng (được đặt bằng phương thức jQuery datitable (), tham chiếu cùng một bảng) có cùng tên với id. Tôi đang cố gắng để có được biến đó, để truy cập các hàm của nó (trên thực tế, để thêm lớp "row_selected" vào hàng đã chọn), khi bảng được nhấp. Kể từ khi tôi viết bài này, tôi đã đưa ra một cải tiến, tuy nhiên. Tôi chỉ đặt tất cả các tham chiếu đối tượng trong một mảng, đặt tên cho các phần tử giống như id và cắm chuỗi id vào đó để lấy đối tượng ref.
BobRodes

Brian, nếu bạn có một phương tiện tốt hơn để tìm id của bảng đã được nhấp, tôi sẽ nghe thấy. Đối với hàm datatables, tôi cần xử lý sự kiện nhấp vào ô và thêm lớp row_selected vào chaNode của nó. Tại sao tôi không thể xử lý sự kiện hàng và thêm lớp trực tiếp vào nó mà tôi không biết, nhưng hàng không hiển thị như đã chọn khi tôi làm điều đó.
BobRodes

1
Có lẽ tôi không làm cho mình rõ ràng. Nếu bạn gọi eval trên một chuỗi đơn giản (nghĩa là không phải là JS), bạn sẽ ném một ngoại lệ. Vì vậy, việc bạn sử dụng eval không có ý nghĩa. Nếu bạn tình cờ tạo ra một biến đối tượng có cùng tên với id, mã của bạn sẽ hoạt động ... nhưng lại khiến tôi như bị hỏng. Tôi muốn tạo ra biến bằng cách sử dụng document.getElementById(ID).MySpecialProperty = MYSPECIALPROPERTYVALUE(không phải nói là tuyệt vời, nhưng nó tốt hơn eval). Như Eric Lippert chỉ ra, "mọi đối tượng trong JScript đã là một bảng tra cứu."
Brian

Ok, vậy bạn đang nói thêm thuộc tính vào tham chiếu phần tử và đặt thuộc tính đó vào tham chiếu đối tượng có thể truy cập được? Điều đó nghe có vẻ chặt chẽ hơn đối với tôi là tốt.
BobRodes
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.