如何让 Jackson 在输出字符串中转义 </script>?

How to get Jackson to escape a </script> in output string?

我有一个简单的 Java 对象,我正在使用 Jackson 将其序列化为 JSON,然后我将其放入 [=32] 中的 <script> 标记中=] 页面作为初始化 JavaScript 对象的一部分。例如

<script>SomeLib.load(${someObject});</script>

这很好除非 someObject 的字段之一是包含 "</script>" 的字符串,因为 this issue。也就是说,如果输出如下所示:

<script>SomeLib.load({"someValue":"hacked!</script>"});</script>

然后浏览器(目前已在 Chrome 和 FF 中测试)相信 hacked! 之后的 </script> 标签正在关闭脚本标签。这会破坏 Java 脚本并使 "});</script> 对用户可见。

有没有办法让 Jackson 以某种方式摆脱这个值来解决这个问题?

您可以使用 JSTL 函数 fn:replace()< 转义为 &lt;,这将有效地阻止 JSON 中的任何标记string 被解释为 HTML.

所以,这个

<script>SomeLib.load(${fn:replace(jsonString, "<", "&lt;")});</script>

在浏览器中可以很好地呈现为

<script>SomeLib.load({"someValue":"hacked!&lt;/script>"});</script>

但是,在使用 replace() 之前,您需要导入 JSTL functions 标签库作为

<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>

No, that won't work because the < will literally be in that JavaScript string (it is not unescaped).

这就是重点,因为如果它以 < 形式出现,它会破坏 HTML parser/browser.

您需要记住,当协议或应用程序对某些内容进行编码时(例如 URL 由浏览器以 UTF-8 编码的字符串),它也需要在使用之前进行解码(例如网络服务器在服务器端处理 URL),否则功能可能会中断。

所以,现在您知道您的 JSON 字符串是半编码的,您还需要修改消费者;用 < 替换 &lt;SomeLib.load() 方法,或者如果这是第三方库,则在 Javascript 本身中解码其输入。

<script>
  var json = '${fn:replace(jsonString, "<", "&lt;")}';
  SomeLib.load(JSON.parse(json.replace("&lt;", "<")));
</script>

是错误的。在那里查看我的评论。

更好的方法是用反斜杠转义 </ 中的斜杠,例如:

<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
...
<script>SomeLib.load(${fn:replace(jsonString, "</", "<\/")});</script>

注意:需要两个反斜杠,因此第一个反斜杠在 JSP 语法中被转义。

优点是不需要特殊解码。

PS:要在 Jackson 方面执行此操作,请参阅 this blog - 它涵盖了转义其他字符,但只需将斜杠添加到列表中即可转义(所有)斜杠字符。