视觉相似的字符

更新

黑客通类似的原理攻击了加密货币(crypto)Sats,一个Unicode Character “ʦ” (U+02A6)在数据库索引时编码和ts也很接近,因此搜索Sats时会搜到Saʦ,看上去就像是UI的简单问题。因此黑客挂单假的Sats货币,赚取了很多钱。

如果当时能深入思考,我也能捞一大笔也说不定。错失数亿。

起源

视觉相似的字符可以从一个社会新闻谈起,某明星用不同的入炸话题, 另一个例子防止代码出错我需要选用不会混淆1和I的字体。在帮朋友写一个转换经纬度单位的程序的时候就遇到了相似字体的问题。

案例

经纬度Degrees Minutes Seconds 我需要转换为 Decimal Degrees,一开始默认代码是E或者N,W,S,由于他的经纬度是手动从文章复制的,所以出现了一些奇怪的问题。

  1. 我只判断了是否要加上负号,没有对非WS的情况检验,默认不是WS就是EN了,事实上他的WS后面常常有空格,用Strip()方法可解,但一开始的忽略会导致有些负号没有加上。
  2. 异体字希腊字母也是我没有考虑到的,事实上查看ASCII码可以发现看似是E和N的其实不是,例如 NNEE 可以是希腊字母。
1
2
if 'E'== 'Ε'
# return False
1
2
if 'N' == 'Ν'
# return False

下面是加了异体字监测部分的转换代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
def dms2dd(dms):
"""
convert degree minute second to degree decimal
:param dms:度分秒/度分 形式的经纬度
:return:
"""
dms = dms.strip()
a = re.findall('[^\\d°\'"″NSEWΕ\\.]', dms)
if a :
print('有异体字符')
print(a)
print('该异体字ASCII是')
print([ord(x) for x in a])
parts = re.split('[°\'"″]+', dms)
degree, minute, second, direction = 0, 0, 0, 0
if len(parts) == 3:
degree, minute, direction = parts
elif len(parts) == 4:
degree, minute, second, direction = parts
dd = float(degree) + float(minute) / 60 + float(second) / (60 * 60)
if direction == 'W' or direction == 'S':
dd *= -1
else:
if direction == 'E' or direction == 'N' or direction == 'Ε' or direction == 'Ν':
dd *= +1
return dd