8
(def evil-code (str "(" (slurp "/mnt/src/git/clj/clojure/src/clj/clojure/core.clj") ")" ))
(def r (read-string evil-code ))

有效,但不安全

(def r (clojure.edn/read-string evil-code))
RuntimeException Map literal must contain an even number of forms  clojure.lang.Util.runtimeException (Util.java:219)

不工作...

如何安全地将 Clojure 代码(保留所有 '#'s 本身是可取的)读入树中?想象一个 Clojure 防病毒软件,它想要扫描代码中的威胁并想要使用数据结构,而不是纯文本。

4

3 回答 3

4

首先,您永远不应该直接从不受信任的数据源中读取 clojure 代码。您应该改用 EDN 或其他序列化格式。

话虽如此,自 Clojure 1.5 以来,有一种无需评估即可读取字符串的安全方法。在使用 read-string 之前,您应该将read-eval var 绑定为 false。在 Clojure 1.4 和更早的版本中,这可能会导致调用 java 构造函数引起的副作用。这些问题已经得到解决。

这是一些示例代码:

(defn read-string-safely [s]
  (binding [*read-eval* false]
    (read-string s)))

(read-string-safely "#=(eval (def x 3))")
=> RuntimeException EvalReader not allowed when *read-eval* is false.  clojure.lang.Util.runtimeException (Util.java:219)

(read-string-safely "(def x 3)")
=> (def x 3)

(read-string-safely "#java.io.FileWriter[\"precious-file.txt\"]")
=> RuntimeException Record construction syntax can only be used when *read-eval* == true  clojure.lang.Util.runtimeException (Util.java:219)

关于阅读器宏

调度宏 (#) 和标记文字在读取时被调用。Clojure 数据中没有它们的表示,因为到那时这些构造都已被处理。据我所知,没有内置方法可以生成 Clojure 代码的语法树。

您将不得不使用外部解析器来保留该信息。您可以使用自己的自定义解析器,也可以使用 Instaparse 和 ANTLR 等解析器生成器。可能很难找到其中任何一个库的完整 Clojure 语法,但您可以扩展其中一个 EDN 语法以包含额外的 Clojure 形式。一个快速的谷歌揭示了 Clojure 语法的 ANTLR 语法,如果需要,您可以更改它以支持缺少的结构。

还有Sjacket是为 Clojure 工具制作的库,需要保留有关源代码本身的信息。这似乎很适合您尝试做的事情,但我个人对此没有任何经验。从测试来看,它的解析器确实支持阅读器宏。

于 2014-07-04T14:01:11.443 回答
2

根据当前文档,您不应该使用也不read应该read-string从不受信任的数据源中读取。

WARNING: You SHOULD NOT use clojure.core/read or
clojure.core/read-string to read data from untrusted sources.  They
were designed only for reading Clojure code and data from trusted
sources (e.g. files that you know you wrote yourself, and no one
else has permission to modify them).

您应该使用read-ednclojure.edn/read考虑到该目的而设计的。

邮件列表中关于使用 read 和read-eval以及关于这些的最佳实践进行了长时间的讨论。

于 2013-04-21T20:43:51.187 回答
0

我想指出一个旧库(在 LightTable 中使用),它使用read-string一种技术来提出客户端/服务器通信

Fetch:用于客户端/服务器交互的 ClojureScript 库

您可以特别看到safe-read方法:

(defn safe-read [s]
  (binding [*read-eval* false]
    (read-string s)))

你可以看到绑定*read-eval*到的使用false。我认为其余代码值得关注它提出的抽象类型。

PR中,建议存在可以通过使用edn来解决的安全问题(...aaand back to your question):

(require '[clojure.edn :as edn])

(defn safe-read [s]
    (edn/read-string s))
于 2015-08-18T14:10:39.973 回答