做内容安全审查时,发现了一个奇怪的case。 明明用户的评论中含有敏感词,但是用关键词匹配却无法匹配成功。就好像like
这个匹配方法失效了一样。
sql select '一个敏感词啊' like '%敏感词%' -- 结果竟然为false
用肉眼是无法看出问题的,把评论以文件形式下载到本地,用vim打开,才发现,原来文本的顺序是错乱的!见下图
以这一段文本为例,<202d><202e>耳木<202c><202c>品质差别<202d><202e>大太<202c><202c>
,看起来是木耳品质差别太大
,但是存储的却是耳木
和 大太
。这样,用普通的方法,便是无法进行字符串匹配,从而逃过了安全审核。
这其实是unicode提供的一个功能,有一些unicode是控制字符。\u202e
的含义就是后面的字符翻转显示,\u202c
的含义是翻转控制到此结束。所以,在这两个控制字符之间的内容,全都是从右向左展示。
查询了一下,unicode相关的控制字符其实还有很多参考链接
开头 | 结尾 | 说明 |
---|---|---|
\u2066 | \u2069 | 之间的字符从左到右显示,不影响外围字符 |
\u2067 | \u2069 | 之间的字符从右到左显示,不影响外围字符 |
\u2068 | \u2069 | 之间的字符以第一个方向设定字符为准 |
\u202A | \u202C | 之间的字符从左到右显示,可以影响外围字符 |
\u202B | \u202C | 之间的字符从右到左显示,可以影响外围字符 |
\u202D | \u202C | 之间的字符按照内存中的顺序,从左到右显示 |
\u202E | \u202C | 之间的字符按照内存中的顺序,从右到左显示 |
也可以在这个网站查询unicode具体的含义https://www.fileformat.info/info/unicode/char/202e/index.htm
虽然unicode里面定义了,但是实现的实现却各有不同,有的可以生效,有的无法生效。在hive中只有\u202E
是生效的。
有了这些知识,翻转字符串变得简单了,只要在最前面加一个 \u202E
即可实现翻转。
select
'hello world',
'\u2067hello world\u2069',
'\u202Bhello world\u202C',
'\u202Ehello world'
这个sql只有最后一个hello world可以被翻转。
翻转字符带来很多麻烦,为了识别出实际展示的字符串,可以制作一个udf把实际展示的字符串翻译出来。java 本身已经内置了一个java.text.Bidi
来方便进行处理。
import org.apache.hadoop.hive.ql