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

时间:2016-01-15 14:58:56

标签: security lisp common-lisp

如何在Common Lisp中安全地解析不受信任的输入?鉴于没有parse-float等,read-from-string将执行读取器宏,如#。 (读取时间eval)。

e.g。     (read-from-string"#。(+ 1 2)")=> 3

2 个答案:

答案 0 :(得分:7)

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

  • 使用with-standard-io-syntax确保您使用标准的readtable等进行阅读。请注意,这会将 * read-eval * 绑定为true,因此请务必使用也:
  • *read-eval*绑定为false( 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))

答案 1 :(得分:2)

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

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