在Clojure/Compojure中对用户输入进行转义/清理

14

我正在使用Clojure/Ring/Compojure-0.4/Enlive堆栈构建web应用程序。

在这个堆栈中是否有函数可以剥离HTML或HTML编码(例如将<a>编码为&lt;a&gt;),以防止XSS攻击?

3个回答

19

hiccup.util/escape-htmlhiccup库中实现,该函数曾经存在于Compojure自身中(因为Hiccup的所有功能曾经是Compojure的一部分)。不过这是一个足够简单的函数,你完全可以自己编写。

(defn escape-html
  "Change special characters into HTML character entities."
  [text]
  (.. #^String (as-str text)
    (replace "&" "&amp;")
    (replace "<" "&lt;")
    (replace ">" "&gt;")
    (replace "\"" "&quot;")))

还有一个 clojure.contrib.string/escape 函数,它接受一个 char -> string 转义序列的映射和一个字符串,然后为您进行转义。

user> (clojure.contrib.string/escape {\< "&lt;" \> "&gt;"} "<div>foo</div>")
"&lt;div&gt;foo&lt;/div&gt;"

我觉得这个方法可能不如它本应该的有用,因为你可能想要转义多个字符的序列,而这个方法做不到。但如果你只需要对HTML进行转义,这个方法或许能够满足你的需求。

当然了,也有很多Java库可以实现这个功能。你可以使用Apache Commons中的StringEscapeUtils库。

(org.apache.commons.lang.StringEscapeUtils/escapeHtml4 some-string)

不过对于这个目的来说,这让我感觉有点过重。


1
StringEscapeUtils的正确URL是http://commons.apache.org/lang/api-release/org/apache/commons/lang/StringEscapeUtils.html。 - grm
更新的URL为http://commons.apache.org/proper/commons-lang/javadocs/api-3.1/org/apache/commons/lang3/StringEscapeUtils.html。 - Jaime Agudo

15
更新:我知道这不仅仅是那些... ring.util.codec 是来自 ring-core 的一个函数集合,这里有一些���数的操作方式:
user> (require '[ring.util.codec :as c])
nil
user> (c/url-encode "<a>")
"%3Ca%3E"
user> (c/url-decode "<a>")
"<a>"

这些是对java.net.URLEncoderjava.net.URLDecoder的封装。同一命名空间提供了基于来自Apache Commons的类的Base64编码处理函数。

以下是原回答。

我不确定是否有公共函数可以做到这一点,但是Enlive有两个私有函数名为xml-strattr-str可以实现此功能:

(defn- xml-str
 "Like clojure.core/str but escapes < > and &."
 [x]
  (-> x str (.replace "&" "&amp;") (.replace "<" "&lt;") (.replace ">" "&gt;")))

(attr-str会转义"。)
你可以使用@#'net.cgrand.enlive-html/xml-str来获取该函数(Clojure不倾向于将事物真正变成私有的...),或者将它复制到你自己的命名空间中。

有点遗憾。听起来在大多数Clojure Web框架中都是一个重大疏忽。 - Alex B
1
显然情况并不是那么糟糕:请查看更新的答案。 :-) - Michał Marczyk
1
看起来我有点草率地责怪了Enlive,但无论如何还是谢谢。 :) - Alex B
2
URL编码并不等同于HTML编码。 url-encode("<a>") => "%3Ca%3E" 而 html-encode("<a>") => "<a>" - Siddhartha Reddy
Siddhartha Reddy:好的,我似乎在发布原始答案和进行编辑之间忘记了规范 - 感谢您指出。至少两个选项都可以使用户输入安全。*(叹气)* 无论如何,xml-str确实使用&foo;实体;很遗憾它是私有的。当然,根据上述问题,Brian的答案确实最合适。 - Michał Marczyk

4
原来Enlive在使用net.cgrand.enlive-html/content将文本放入HTML元素时,默认会进行HTML转义。
(sniptest "<p class=\"c\"></p>" [:.c] (content "<script></script>"))
"<p class=\"c\">&lt;script&gt;&lt;/script&gt;</p>"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接