Java:检测不正确的控制字符JSON

17

我正在重新发明轮子,并在Java中创建自己的JSON解析方法。

我参考了(非常好!)json.org上的文档。我唯一不确定的部分是它说到"或控制字符"

由于文档非常清晰,而且JSON非常简单易懂,我认为我应该按照规范要求而不是放任自流。

如何在Java中正确地去除控制字符?也许有一个Unicode范围?

enter image description here


编辑:拼图中(常见的?)缺失的一块

已经被告知,除了定义范围内的 1 2,还有其他控制字符可以在<script>标签中引起麻烦。

最明显的是U+2028和U+2029字符,即行分隔符和段落分隔符,它们作为换行符。将换行符注入到字符串文字的中间很可能会导致语法错误(未终止的字符串文字)。3

虽然我认为这不构成XSS威胁,但在<script>标签的使用中添加额外规则仍然是个好主意。

  • 只需简单地使用\u符号对所有非“ASCII可打印”字符进行编码。这些字符本来就不常见。如果您愿意,可以添加到白名单中,但我建议采用白名单方法。
  • 如果您不知道,请不要忘记</script(不区分大小写),它可能会通过字符</script><script src=http://tinyurl.com/abcdef>向您的页面注入HTML脚本。默认情况下,JSON不对这些字符进行编码。

1
Unicode 就是 Unicode。UTF-16 是一种编码方式。我认为 Java 有针对 Unicode 分组的测试?请参阅 Character 类文档 以获取一些前置内容和其他有趣的函数。 - user166390
我的意思是,Java字符串中的每个字符都是两个字节。即使数据是ASCII,当转换为字符串时,每个字符串最终也会占用两个字节。 - 700 Software
对于那些不知道的人来说,Java使用UTF-16字符。嗯,是的,有点像。Java的“String”类型在内部以UTF-16存储字符串数据,但Java可以很好地使用其他编码(包括常用的UTF-8或Windows-1252和UTF-32)进行读写操作。可能值得从这里开始:http://www.joelonsoftware.com/articles/Unicode.html - T.J. Crowder
不用担心,即使我没有描述得很准确,我也理解字符串编码。 - 700 Software
4个回答

9

你会使用Character.isISOControl(...)吗?顺便提一下,UTF-16是Unicode代码点的编码... 你将以字节级还是字符/代码点级别进行操作?我建议将UTF-16到字符流的映射留给Java的核心API处理...


我正在字符级别上操作。在JSON解析开始之前,字节会被转换为字符串。 - 700 Software
我不确定isISOControl是否正确。但我知道这样做是可以的,因为它不需要严格正确。 :) - 700 Software
2
@George:好的,文档上说:“如果一个字符的代码在'\u0000'到'\u001F'范围内或在'\u007F'到'\u009F'范围内,则该字符被认为是ISO控制字符。”由于这与我链接的Unicode控制字符的定义相匹配,所以我想@Dilum是正确的... :-)(虽然作为我这样的学究,我可能想找到一份参考资料,证明这两者确实是相关联的,这样如果其中一个更改了,我就不必担心它们会失步。)但这可能只是学究气。 - T.J. Crowder
@T.J.:向你和jarnbjo致敬。接受Dilum的答案,因为那正是我最终使用的。 - 700 Software
@George:完全合理! :-) - T.J. Crowder

6
即使不是非常具体,我认为他们指的是Unicode规范中的"控制字符类别"
在Java中,您可以使用以下表达式检查字符c是否为Unicode控制字符:Character.getType(c) == Character.CONTROL

5

我知道这个问题已经被问过几年了,但我仍然回复,因为接受的答案是不正确的。

Character.isISOControl(int codePoint) 

以下是检查的内容:

(codePoint >= 0x00 && codePoint <= 0x1F) || (codePoint >= 0x7F && codePoint <= 0x9F);

JSON规范在https://www.rfc-editor.org/rfc/rfc7159中定义了以下内容:
  1. 字符串

字符串的表示与C语言家族中使用的约定类似。字符串以引号开头和结尾。除了必须转义的字符(引号、反斜杠和控制字符(U+0000到U+001F))外,所有Unicode字符都可以放在引号内。

Character.isISOControl(int codePoint) 

将标记所有需要转义的字符(U+0000-U+001F),但也会标记不需要转义的字符(U+007F-U+009F)。不过,不需要转义字符(U+007F-U+009F)


4

我认为控制字符的Unicode定义是:

范围在U+0000..U+001F和U+007F..U+009F之间的65个字符。

这是它们被定义为控制码,但上面还跟着一句话"也被称为控制字符。",因此...


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