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

Security 如何在Common Lisp中安全地解析不受信任的输入?,security,lisp,common-lisp,Security,Lisp,Common Lisp,如何在Common Lisp中安全地解析不受信任的输入?假设不存在解析浮点等,并且从字符串读取将执行#之类的读取器宏。(读取时间评估) e、 g。 (从字符串“#.(+12)”中读取)=>3我找不到描述Common Lisp的一些安全输入处理过程的其他问题或注释(如果其他人找到了,请发表注释!),但至少有两件重要的事情可以做: 使用以确保您正在使用标准可读表等进行阅读。请注意,这会将*read eval*绑定为true,因此请确保: 绑定到false(使用标准io语法在内)。这将禁用问题中提到

如何在Common Lisp中安全地解析不受信任的输入?假设不存在解析浮点等,并且从字符串读取将执行#之类的读取器宏。(读取时间评估)

e、 g。
(从字符串“#.(+12)”中读取)=>3

我找不到描述Common Lisp的一些安全输入处理过程的其他问题或注释(如果其他人找到了,请发表注释!),但至少有两件重要的事情可以做:

  • 使用以确保您正在使用标准可读表等进行阅读。请注意,这会将*read eval*绑定为true,因此请确保:
  • 绑定到false(使用标准io语法在内)。这将禁用问题中提到的sharpsign点(#)宏
(let((*readtable*(copy readtable)))
(设置宏字符#\n(持续“注入”)
(从字符串“(#.(+25)n)”读取)
;;=> (7)
(let((*readtable*(copy readtable)))
(设置宏字符#\n(持续“注入”)
(使用标准io语法)
(let((*读eval*nil))
(从字符串“(#.(+25)n)”读取)
;; 对#的评估已中止。
(let((*readtable*(copy readtable)))
(设置宏字符#\n(持续“注入”)
(列表(从字符串“(n)”读取)
(使用标准io语法)
(let((*读eval*nil))
(从字符串“(n)”中读取)
;; ((注)(N))

一般来说,标准代码读取器非常方便,可以读取多种输入,但这并不意味着您应该使用它来读取除代码以外的任何内容


有很多库可以解析很多东西,例如。g<代码>解析数字对于Lisp数字格式,对于csv文件(在许多其他csv库中),
json流
对于json(同样,许多其他库)。对于大多数格式,您只需使用Quicklisp执行
系统apropos
查找。

请注意,您可以禁用#。使用
*读取eval*
。也就是说,很难做到完全安全,因为读者可以调用其他类型的宏。最近,有人在Common Lisp中写了一些关于安全输入处理的好注释(现在就开始查找)。此外,如中所述,请查看。我知道这是一个示例,但如果您只想解析浮点,请参阅“假设没有解析浮点等”,这也有点宽泛。有一些解析函数,但不是全部。例如,有一个标准解析整数。实现也可能提供其他功能。例如,Lispworks确实有一个。请确保使用标准io语法将
*read eval*
重新绑定到
中的
NIL
,因为后者会将其绑定到其默认值
T
@RainerJoswig对子弹物品进行了重新排序,并做了一些解释。
(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))