你如何安全地解析 Common Lisp 中不受信任的输入?

How do you securely parse untrusted input in Common Lisp?

如何在 Common Lisp 中安全地解析不受信任的输入?假设没有 parse-float 等,并且 read-from-string 将执行 reader 宏,如 #。 (读取时间评估)。

例如 (从字符串中读取 "#.(+ 1 2)") => 3

我找不到描述 Common Lisp 的一些安全输入处理程序的其他问题或评论(如果有人找到它们,请 post 发表评论!),但至少有您可能会做两件重要的事情:

  • 使用 with-standard-io-syntax 确保您正在使用标准可读表等进行阅读。请注意,这会将 *read-eval* 绑定为 true , 所以一定要:
  • *read-eval* 绑定为 false (within with-standard-io-syntax)。这将禁用问题中提到的 sharpsign-dot (#.) 宏。
(let ((*readtable* (copy-readtable)))
  (set-macro-character #\n (constantly 'injected))
  (read-from-string "(#.(+ 2 5) n)"))
;;=> (7 INJECTED)

(let ((*readtable* (copy-readtable)))
  (set-macro-character #\n (constantly 'injected))
  (with-standard-io-syntax
    (let ((*read-eval* nil))
      (read-from-string "(#.(+ 2 5) n)"))))
;; Evaluation aborted on #<SB-INT:SIMPLE-READER-ERROR
;; "can't read #. while *READ-EVAL* is NIL" {1004DA3603}>.

(let ((*readtable* (copy-readtable)))
  (set-macro-character #\n (constantly 'injected))
  (list (read-from-string "(n)")
        (with-standard-io-syntax
          (let ((*read-eval* nil))
            (read-from-string "(n)")))))
;; ((INJECTED) (N))

一般来说,标准代码 reader 如此容易获得并且可以读取多种输入并不意味着您应该使用它来读取代码以外的任何内容。

有很多库可以解析很多东西,例如。 G。 parse-number 用于 Lisp 数字格式,fare-csv 用于 CSV 文件(在许多其他 CSV 库中),json-streams 用于 JSON(同样,许多其他)。对于大多数格式,您只需使用 Quicklisp 进行 system-apropos 查找。