【问题标题】:In Clojure, how can I secure the "resolve" function for user input?在 Clojure 中,如何保护用户输入的“解析”功能?
【发布时间】:2019-09-30 23:51:16
【问题描述】:

我的问题

我目前正在编写一个 REST-API,它应该接受 JSON 请求并使用我们使用的实习生库。主要用途是使用 Web 界面运行服务器,或者可能使用另一种语言来处理 API,因为 Clojure 在其他地方并不常见。

为了实现这一点,JSON 请求包含数据和函数名,它使用解析运行,因为我应该这样做,这样我们就不必在每次添加函数时更改 API/删除。

现在实际的问题是:如何确保我运行的函数与它的参数结合起来不会破坏整个事情?

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

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

另一件事是输入。 我再次有了一个基本想法,即清理输入以替换各种括号,以确保输入不是其他只会绕过上面的命名空间限制的 clojure 代码。但这真的就足够了吗?我没有太多破坏东西的经验。

我听到的另一个担忧是,某些函数可能会提前将输入作为参数运行。服务器使用 ring 及其 JSON 扩展。 JSON 应该只提供字符串、数字、布尔值和 nil 作为原子数据类型。我得出结论,每个可能的恶意输入都应该是我最后的一个字符串 - 除了解析之外,是否有任何函数可能会产生运行此类输入的副作用? 由于它们是字符串:是否需要担心数据?

【问题讨论】:

  • 除非您评估输入(假设您基本上是指要解析的函数的参数),否则没有一般问题。 JSON 表示纯数据。但是由于您已经在谈论清理括号 (?),如果您可以展示您计划接受的请求的示例,那么 tt 将非常有帮助。
  • @cfrick 另一个输入只是作为函数的参数,没错。出现了对数据的担忧,因为有可能只使用评估数据的函数。白名单方法似乎可以防止这种情况发生,但我只是想确保以防某些不应该被列入白名单的情况。

标签: clojure


【解决方案1】:

我强烈建议对函数使用白名单方法,而不是评估其他任何内容。

您可以将元数据标志添加到您检查解决它们的位置的公开函数。

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

【讨论】:

    【解决方案2】:

    您可能想查看以下内容:

    • 如何确定来自给定命名空间的公共函数。这将为您提供 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?),否则您可能会接受您无法满足的请求,因为这些功能已更改或可能被删除。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-11-10
      • 2013-08-26
      • 2014-06-12
      • 2019-03-29
      • 1970-01-01
      • 1970-01-01
      • 2014-04-01
      相关资源
      最近更新 更多