如何让 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()
将 <
转义为 <
,这将有效地阻止 JSON 中的任何标记string 被解释为 HTML.
所以,这个
<script>SomeLib.load(${fn:replace(jsonString, "<", "<")});</script>
在浏览器中可以很好地呈现为
<script>SomeLib.load({"someValue":"hacked!</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 字符串是半编码的,您还需要修改消费者;用 <
替换 <
的 SomeLib.load()
方法,或者如果这是第三方库,则在 Javascript 本身中解码其输入。
<script>
var json = '${fn:replace(jsonString, "<", "<")}';
SomeLib.load(JSON.parse(json.replace("<", "<")));
</script>
是错误的。在那里查看我的评论。
更好的方法是用反斜杠转义 </
中的斜杠,例如:
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
...
<script>SomeLib.load(${fn:replace(jsonString, "</", "<\/")});</script>
注意:需要两个反斜杠,因此第一个反斜杠在 JSP 语法中被转义。
优点是不需要特殊解码。
PS:要在 Jackson 方面执行此操作,请参阅 this blog - 它涵盖了转义其他字符,但只需将斜杠添加到列表中即可转义(所有)斜杠字符。
我有一个简单的 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()
将 <
转义为 <
,这将有效地阻止 JSON 中的任何标记string 被解释为 HTML.
所以,这个
<script>SomeLib.load(${fn:replace(jsonString, "<", "<")});</script>
在浏览器中可以很好地呈现为
<script>SomeLib.load({"someValue":"hacked!</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 字符串是半编码的,您还需要修改消费者;用 <
替换 <
的 SomeLib.load()
方法,或者如果这是第三方库,则在 Javascript 本身中解码其输入。
<script>
var json = '${fn:replace(jsonString, "<", "<")}';
SomeLib.load(JSON.parse(json.replace("<", "<")));
</script>
更好的方法是用反斜杠转义 </
中的斜杠,例如:
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
...
<script>SomeLib.load(${fn:replace(jsonString, "</", "<\/")});</script>
注意:需要两个反斜杠,因此第一个反斜杠在 JSP 语法中被转义。
优点是不需要特殊解码。
PS:要在 Jackson 方面执行此操作,请参阅 this blog - 它涵盖了转义其他字符,但只需将斜杠添加到列表中即可转义(所有)斜杠字符。