在2024年的 Clojure 状态调查中分享您的看法!(https://www.surveymonkey.com/r/clojure2024)

欢迎!请查阅“关于”页面以了解更多关于其工作方式的信息。

+1 投票
语法和读取器

我是Clojure的新手,正在尝试理解该语言的一些安全特性。

在文档中,我了解到将read-eval绑定到未知应该会拒绝代码执行。

但是,在clojure.core/read-string中尝试代码时,clojure.tools.reader/read-string会正确地调用。

我还看到reader.edn不会调用代码,但我想确认即使我们的开发者不小心使用了clojure.tools.reader,也不会执行任何代码。

谢谢,Rotem

原型

(binding [*read-eval* :unknown]
(clojure.tools.reader/read-string "#=(* 2 21)"))
=> 42

1 个回答

+1 投票

如果他们“意外”包含一个额外的库并调用任意代码,那么他们可以意外地做任何事情。

clojure.tools.reader有一个类似的动态var,clojure.tools.reader/*read-eval*,它以同样的方式使用,所以您需要绑定两个。

明白了,我想在测试中将一个 *read-eval* 设置为未知,以验证没有代码正在运行,就像 clojure.core 不需要 clojure.core/*read-eval* 绑定一样。

是的,在安全方面,我想确保开发者知道他们想要评估功能。我建议将其默认设置为 false,但这是一个更加核心的需求。

我建议添加适当的文档,因为这并不清楚,可能在我们没有考虑的可能位置创建代码执行。
这里的 clojure.core/read 和 clojure.core/read-string 文档是否澄清了任何问题?这是在 clojure.edn 命名空间被添加到 Clojure 几年前写的,对我个人来说仍然似乎准确:[链接](https://docs.clojure.org/clojure.core/read)
这里的混淆是否是因为这个文档没有明确指出它提到的 *read-eval* 是哪一个?

[文档链接](http://clojure.github.io/tools.reader/#clojure.tools.reader/read-string)

我可以理解,有人可能只阅读了 core read/read-string 文档,然后阅读了 tools.reader 的文档中的 read/read-string,但没有意识到它指的是一个独立的 clojure.tools.reader/*read-eval*,而不是核心变量。

我也可以理解,为什么一些人想要将核心变量绑定,希望它能够“普遍”适用(例如,可能会控制某些 Contrib 库的行为——假设 Contrib 库属于 Clojure 组织,因此它们可能存在一定的相互依赖性)。
Sean,我认为这正是我的想法和困惑。

我发现很多Clojure开发者使用read-string而不真正理解其对安全性的影响。即使尝试使用*read-eval*符号来禁用它,也会变得混淆。在这场讨论中,我了解到我需要放置不同命名空间下的两个绑定。

我希望有一个可以放置的绑定,可以确信在这些常见的read-string函数中不会有eval。
一个很好的方法就是教育开发人员关于clojure.core/read和clojure.core/read-string的不安全性,例如,让他们看看我给出的链接上的示例。

另一个方法是为他们提供一些你信任的、安全的函数,并建议他们使用这些函数。你可以对他们进行注释或在文档字符串中尽情地写长篇大论,说明为什么它们更安全,以及为什么替代方案不安全。

现成的替代品是为了让那些使他们的代码更安全的人方便。仍然需要教育,使他们了解函数的存在。
...并劝阻他们使用tools.reader函数——这是一个常见的传递依赖,因此我可以看到它们如何在代码库中找到它,并认为使用“reader”命名空间读取字符串是显然的、正确的方式。
...