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

4

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

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

这个方法非常好用,除非 someObject 中的某个字段是一个包含 "</script>" 的字符串,由于这个问题。也就是说,如果输出结果看起来像这样:

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

然后浏览器(已在Chrome和FF中进行了测试)认为</script>标记位于hacked!之后,从而关闭脚本标记。这会导致JavaScript出错,并使"});</script>对用户可见。

是否有一种方法可以让Jackson以某种方式转义该值以解决此问题?


1
只需转义XML,您需要一个库来完成这项任务,除非您可以使用JSTL。但是,由于看起来您正在使用某种标签库,请使用JSTL函数库的escapexml,或者使用默认情况下转义XML的核心JSTL库“out”。 - Zachary Craig
@zack6849 这不完全正确,因为 escapeXml="true" 也会转义引号,结果会变成 {&#034;someValue&#034;:&#034;hacked!</script>&#034;} - jwl
转义斜杠“/”是我经常看到的一种常见模式,以应对这种“攻击”。https://dev59.com/1Yfca4cB1Zd3GeqPjXtU - pozs
2个回答

4

Ravi的回答 是错误的。请看我在那里发表的评论。

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

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

注意:在JSP语法中,需要两个反斜杠来转义第一个反斜杠。
好处是不需要特殊解码。
PS: 如果要在Jackson端执行此操作,请参见这篇博客 - 它涵盖了转义其他字符的内容,但只需将斜杠添加到转义(所有)斜杠字符列表中即可。

0
你可以使用JSTL函数fn:replace()来转义仅以<开头的字符,用&lt;代替,这将有效地防止JSON字符串中的任何标签被解释为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" %>

不,那样行不通,因为“<”会被直接放在JavaScript字符串中(它没有被转义)。
这正是问题所在,因为如果它输出为“<”,那么它将破坏HTML解析器/浏览器。
需要记住的是,当协议或应用程序对某些内容进行编码(例如由浏览器编码为UTF-8的URL字符串)时,它也需要在使用之前进行解码(就像Web服务器在服务器端处理URL一样),否则功能可能会出现问题。
因此,现在您知道您的JSON字符串是半编码的,您需要修改消费者;要么修改SomeLib.load()方法以将&lt;替换回<,要么如果那是第三方库,则在JavaScript本身中解码其输入。
<script>
  var json = '${fn:replace(jsonString, "<", "&lt;")}';
  SomeLib.load(JSON.parse(json.replace("&lt;", "<")));
</script>

1
不行,那样做不起作用,因为“<”会被当做 JavaScript 字符串的一部分(它没有被转义)。http://jsbin.com/kemeqagare - jwl
这是错误的。如果原始数据包含"<",那么您的代码将把它弄成"<"。 - David Balažic

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