2010-06-08 33 views
7

Đây thực sự chỉ là một câu hỏi mang tính khái niệm đối với tôi tại thời điểm này.Bảo mật/xác thực dữ liệu Lisp

Trong Lisp, các chương trình là dữ liệu và dữ liệu là các chương trình. REPL thực hiện chính xác điều đó - đọc và sau đó đánh giá.

Vậy làm cách nào để bạn tiếp cận dữ liệu đầu vào từ người dùng một cách an toàn? Rõ ràng là nó có thể - ý tôi là qua mạng - bây giờ Yahoo! Cửa hàng khá an toàn, vậy làm thế nào nó được thực hiện?

Trả lời

16

REPL là viết tắt của Read Eval Print Loop.

(loop (print (eval (read)))) 

Trên đây chỉ là khái niệm, mã REPL thực sự phức tạp hơn nhiều (với xử lý lỗi, gỡ lỗi, ...).

Bạn có thể đọc tất cả các loại dữ liệu trong Lisp mà không đánh giá nó. Đánh giá là một bước riêng biệt - độc lập với việc đọc dữ liệu.

Có tất cả các loại hàm IO trong Lisp. Sự phức tạp nhất của các hàm được cung cấp thường là READ, nó đọc các biểu thức s. Có một tùy chọn trong Common Lisp cho phép đánh giá trong READ, nhưng có thể và nên được tắt khi đọc dữ liệu.

Vì vậy, dữ liệu trong Lisp không nhất thiết là một chương trình và thậm chí nếu dữ liệu là một chương trình, thì Lisp có thể đọc chương trình dưới dạng dữ liệu - mà không cần đánh giá. REPL chỉ nên được nhà phát triển sử dụng và không được tiếp xúc với người dùng tùy ý. Để nhận dữ liệu từ người dùng, người ta sử dụng các hàm IO bình thường, bao gồm các hàm như READ, có thể đọc các biểu thức S, nhưng không đánh giá chúng.

Dưới đây là một vài điều người ta không nên làm:

  • sử dụng READ để đọc dữ liệu tùy ý. ĐỌC ví dụ cho phép một người đọc dữ liệu thực sự lớn - không có giới hạn.

  • đánh giá trong READ ('đọc eval'). Điều này nên được tắt.

  • ký tự đọc từ I/O và gọi chức năng biểu tượng của họ

  • đọc cấu trúc dữ liệu theo chu kỳ với READ, khi các chức năng bạn mong đợi danh sách đơn giản. Đi xuống một danh sách theo chu kỳ có thể giữ cho chương trình của bạn bận rộn trong một thời gian.

  • không xử lý lỗi cú pháp trong khi đọc từ dữ liệu.

+0

+1 câu trả lời hay. – rook

2

Đây là một câu hỏi sát thủ và tôi nghĩ điều tương tự này khi tôi đọc về Lisp. Mặc dù tôi đã không làm bất cứ điều gì có ý nghĩa trong LISP nên câu trả lời của tôi rất hạn chế.

Những gì tôi có thể cho bạn biết là eval()is nasty. Có một câu nói rằng tôi thích "Nếu eval là câu trả lời thì bạn đang đặt câu hỏi sai." --Không xác định.

Nếu kẻ tấn công có thể kiểm soát dữ liệu được đánh giá sau đó bạn có lỗ hổng thực thi mã từ xa rất nghiêm trọng. Điều này có thể được giảm nhẹ, và tôi sẽ chỉ cho bạn một ví dụ với PHP, bởi vì đó là những gì tôi biết:

$id=addslashes($_GET['id']); 
eval('$test="$id";'); 

Nếu bạn không làm một add chém sau đó kẻ tấn công có thể nhận được thực thi mã từ xa bằng cách làm này :

http://localhost?evil_eval.php?id="; phpinfo();/* 

Nhưng add dấu gạch chéo sẽ biến thành một "\", do đó giữ những kẻ tấn công từ "phá vỡ" của các "dữ liệu" và có thể thực thi mã. Đó là rất giống với tiêm sql.

+0

+1 cho báo giá. Điều đó có thể áp dụng cho hầu hết mọi ngôn ngữ. Và tất nhiên bất cứ lúc nào tôi sử dụng php, đầu vào luôn được bao bọc trong một htmlspecialchars() –

6

Bạn làm theo cách mọi người khác làm. Bạn đọc một chuỗi dữ liệu từ luồng, bạn phân tích nó cho các lệnh và tham số của bạn, bạn xác thực các lệnh và tham số, và bạn hiểu các lệnh và tham số.

Không có phép thuật ở đây.

Đơn giản chỉ cần đặt, những gì bạn KHÔNG làm, là bạn không tiếp xúc với người nghe Lisp của bạn đến một nguồn dữ liệu không được xác nhận, không an toàn.

Như đã đề cập, REPL được đọc - đánh giá - in. @ The Rook tập trung vào eval (với lý do), nhưng không giảm giá ĐỌC. READ là một lệnh rất mạnh trong Common Lisp. Người đọc có thể tự đánh giá mã, trước khi bạn thậm chí GET "eval".

KHÔNG hiển thị READ cho bất kỳ điều gì bạn không tin tưởng. Với công việc đủ, bạn có thể tạo gói tùy chỉnh, giới hạn phạm vi chức năng sẵn có cho gói đó, v.v. Nhưng, tôi nghĩ đó là công việc nhiều hơn chỉ đơn giản là viết một trình phân tích cú pháp lệnh đơn giản và không đáng lo ngại về một số tác dụng phụ mà tôi đã bỏ lỡ.

+0

Đó chính xác là nơi mà sự lo lắng của tôi là - người đọc có thể đánh giá mã. Có một số loại tương đương với Python 2.6 'raw_input()' không? –

+1

http://www.lispworks.com/documentation/HyperSpec/Body/f_rd_lin.htm – Ken

0

Tôi thấy rằng câu hỏi đó không gây tranh cãi. Eval sẽ không đánh giá đầu vào của bạn trừ khi bạn yêu cầu nó một cách rõ ràng. Tôi có nghĩa là đầu vào của bạn sẽ không coi đó là mã LISP mà thay vào đó là một chuỗi.

Không phải vì ngôn ngữ của bạn có khái niệm mạnh mẽ như eval rằng nó không phải là "an toàn".

Tôi nghĩ sự nhầm lẫn đến từ SQL, nơi bạn thực sự coi đầu vào là một phần của SQL.

(query (concatenate 'string "SELECT * FROM foo WHERE id = " input-id)) 

Tại đây, id đầu vào đang được công cụ SQL đánh giá. Điều này là do bạn không có cách nào tốt đẹp để viết SQL, hoặc bất cứ điều gì, nhưng điểm là đầu vào của bạn trở thành một phần của những gì đang được đánh giá.

Vì vậy, eval không mang đến cho bạn sự mất an toàn trừ khi bạn đang sử dụng mắt nhắm.

EDIT Hãy quên rằng điều này áp dụng cho bất kỳ ngôn ngữ nào.

4
  1. Tạo bảng đọc của riêng bạn và điền vào các móc cần thiết: BỘ ĐẶC ĐIỂM ĐẶC ĐIỂM, SET-DISPATCH-MACRO-CHARACTER et al.
  2. Bind READTABLE để đọc của riêng bạn.
  3. Ràng buộc READ-EVAL để không ngăn #. (có thể không cần thiết nếu bước 1 được thực hiện đúng)
  4. ĐỌC

Có thể là một cái gì đó khác.

Cũng có một mẹo trong ký hiệu interning trong gói tạm thời trong khi đọc.

Nếu dữ liệu không phải là LL (1) -ish, chỉ cần viết trình phân tích cú pháp thông thường.

Các vấn đề liên quan