有人跟我反馈说有bug。
我说:啥bug?
对方说:刚申请的内部用户的账号登录不上去。
我说:还有这种事,报啥错?
登录的时候报了这个错:
我一看还好还好,跟上一次不一样的错,不然我都觉得我穿越回去了。
我脑子都不动一下,直接回复:是不是输入空格了?我看之前的逻辑是不会自动去除首尾空格的。
对方答:
我不信邪,要到账号密码(密码是建立账号后通过邮箱发送的),自己实验了一下,还真的登不上去。
奇了怪了,这块逻辑我看了下,实现很简单,大概逻辑简化后的代码如下:
- User user = userService.getOne(username,password);
- if (Objects.isnull(user)) {
- throw new Exception("用户或密码错误");
- }
这里的 username 是员工姓名,这个实现我觉得很奇葩...重名了咋办?
搜索条件加了密码避免了重名的情况....
但万一密码一样且重名呢??
理论上这个概率比较低,因为密码够复杂,长度必须为 18 位,且必须包含字母大小写、数字和特殊符号,但是确实是有这个可能,所以为啥不能用手机号当登录账号呢?
算了,不纠结这个,还是来看看为啥登录不上去吧!
看着报错,肯定就是 user 没找到呗,那么我自己输入了一遍账号和密码,确认没输错,于是就怀疑起密码,难道是邮寄发送的密码和数据库实际存储的不一样?
我登上数据库,利用 username 查询这条记录,想对比下密码,发现竟然找不到这条记录??
(假设这个 username 是 aaa)
select * from user where username='aaa';
我的发?难道是账号没生成?
因为发邮件和数据库保存账号肯定不是一个事务操作,所以有几率会发生这种情况。
随即我按照 id 倒序取最新五条看看最近的记录都是啥,又发现有 aaa 这条记录???
我的发?见鬼了吗?
突然开始怀疑这个 username 的格式,直接在阿里云 dms 上点开这个字段,果然发现了猫腻!
可以看到名字中间有红点,而正常的名字中间都是没红点的,那么这个红点是什么玩意?
我把红点拷贝出来,直接一个urlEncode,从界面可以看到输入那边完全看不出有任何东西,但是实际 encode 是有值的:
%E2%80%8B 这又是啥玩意?我直接一个搜索:
零宽空格!!好吧,懂了,破案了,怪不得数据没匹配上!
简单理解就是这个字符正常情况下肉眼不可见,但是它确实存在,所以手输的 aaa 匹配不上存在数据库里面的 aaa,因为数据库的aaa夹了看不见的"内鬼"啊!。
除了零宽空格,还有别的零宽字符,比如零宽非断空格符、零宽度连字符等等,特性都是非打印,即肉眼不可见。
它们可以用来实现隐形水印或者信息加密。
我找了个网站,咱们看看效果:
比如我将'你好'和'好个屁'混合了一下,得到右边的'你好'。
此时复制右边的'你好',decode 以下就能得到隐写的'好个屁':
原理也很简单,将要加密的字符转成二进制,然后按照一定的规则翻译,比如1转成零度空格符、0转成零宽非断空格符,字母间隔用零宽连接符分隔。
然后解密的时候按照上述规则翻译过来即可。
网址贴这里的,有兴趣的可以自己去玩玩 :https://yuanfux.github.io/zero-width-web/
最后我直接把这个姓名重新编辑了一下就好了,操作人员因为是从工单上复制姓名,所以才搞出了这个零宽字符,后续让他手输!