在Clojure中,如何确保用户输入的“解析”功能?

时间:2019-09-30 23:51:16

标签: clojure

我的问题

我目前正在编写一个REST-API,该API应该接收JSON请求并与我们使用的内部库一起工作。主要用法将是通过Web界面运行服务器,或者可能使用其他语言来与API一起使用,因为Clojure在其他地方并不常见。

为了实现这一点,JSON请求包含数据和一个函数名,该函数名通过resolve运行,因为我应该这样做,以便我们不必在每次添加函数时都更改API /删除。

现在的实际问题是:我如何确保运行的函数与其参数相结合不会破坏整个过程?

那么,我已经尝试了什么?

现在,到目前为止,我实际上只讲了一半事实:我不使用resolve,而是使用ns-resolve。我的第一个直觉是创建一个单独的文件,该文件将从库中的所有命名空间加载,您可以用这些文件进行恶意操作。问题是,我只需要那些函数,而我不知道有什么方法可以删除clojure.core函数。我可以为那些人做一个黑名单,但是白名单会容易得多。更不用说我永远找不到我实际上应该列入黑名单的所有核心功能。

其他事情就是输入。 再次,我有一个基本的想法,那就是清理输入以替换所有括号,以确保输入不是其他Clojure代码,而只是从上面绕过名称空间限制。但这实际上足够了吗?我在破坏事物上没有太多经验。

我听说的另一个问题是,某些功能可能早于预期运行输入作为参数。该服务器可以使用ring及其JSON扩展名。 JSON仅应将字符串,数字,布尔值和nil作为原子数据类型。我得出的结论是,每个可能的恶意输入都应该在结尾处是一个字符串-除了解决方案之外,是否有任何功能可能会对运行此类输入产生副作用? 由于它们是字符串,因此:甚至不需要担心数据吗?

2 个答案:

答案 0 :(得分:1)

我强烈建议对功能使用白名单方法,而不要评估其他任何东西。

您可能会向所公开的函数添加元数据标志,以检查在哪里解析它们。

其他一切都应该只是数据;不要评估它。

答案 1 :(得分:0)

可能您想研究以下内容:

  • 如何从给定的命名空间确定公共功能。这将为您提供API可以接受作为输入一部分的有效函数名称的列表。这是一个示例:
user=> (ns-publics (symbol "clojure.string"))
{ends-with? #'clojure.string/ends-with?, capitalize #'clojure.string/capitalize, reverse #'clojure.string/reverse, join #'clojure.string/join, replace-first #'clojure.string/replace-first, starts-with? #'clojure.string/starts-with?, escape #'clojure.string/escape, last-index-of #'clojure.string/last-index-of, re-quote-replacement #'clojure.string/re-quote-replacement, includes? #'clojure.string/includes?, replace #'clojure.string/replace, split-lines #'clojure.string/split-lines, lower-case #'clojure.string/lower-case, trim-newline #'clojure.string/trim-newline, upper-case #'clojure.string/upper-case, split #'clojure.string/split, trimr #'clojure.string/trimr, index-of #'clojure.string/index-of, trim #'clojure.string/trim, triml #'clojure.string/triml, blank? #'clojure.string/blank?}
  • 您可能想要使用上图中的键(在适用于您的用例的名称空间中)来验证输入,因为如果完全限定函数名称,则可以“转义” ns-resolve名称空间:
user=> ((ns-resolve (symbol "clojure.string") (symbol "reverse")) "hello")
"olleh"

user=> ((ns-resolve (symbol "clojure.string") (symbol "clojure.core/reverse")) "hello")
(\o \l \l \e \h) ;; Called Clojure's own reverse, probably you don't want to allow this

现在,话虽如此,我将为您提供一些免费建议:

  

我应该做到这一点,以便我们不必在每次添加/删除函数时都更改API

如果您观看了Rich Hickey的一些演讲,您会知道API更改是一个明智的话题。通常,在添加新功能或删除任何功能之前,您应该仔细考虑,因为听起来您的团队愿意在将API的客户放在同一页面上时走捷径。

除非您的客户端可以动态发现可用的功能(也许您将公开一些API?),否则听起来您将愿意接受由于功能已更改或可以删除​​而无法满足的请求。