ITPUB

用户名叫 “null”,害我 Debug 到凌晨两点,心态崩了!

前几天看到一篇贴子,真的很感同身受——“天才用户取用户名为null,害我熬夜查到两点”……这谁没遇到过类似的bug?

Image

但如果我们要从一个开发者的角度去看,还真得把那层调侃的外衣扒了,看看里面到底踩的是哪门子坑。贴子虽然搞笑,背后的技术问题却一点不轻松,甚至可以说是“祖传坑”。

Image

先说明一下,原帖说的“null”到底是啥意思,这不是Java的null关键字,而是一个字符串,也就是"null",用英文引号括起来的那个,是有内容的,不是空。你把这个当成空值处理,那基本就是在写bug。

这个坑最常见的场景,就是你在做用户注册或者处理输入时,没判断输入的值是不是故意输入的"null",系统就把它当成了一个“真空值”处理,结果各种异常报错就来了。有一次我在写一个后端注册接口,前端传了一个json:

{
"username": "null",
"password": "123456"
}

我当时后台代码是这样的:

if (user.getUsername() == null) {
thrownew IllegalArgumentException("用户名不能为空");
}

你猜怎么着?这段代码屁都没报错,因为"null"这个字符串根本不是null,它是有内容的字符串,结果这个用户就“合法”注册进系统里了。等到要发邮件、要加权限,甚至检查重名时,才发现怎么一个用户叫null,简直像个幽灵。

所以从技术上说,必须明确区分null(空指针)和**"null"(字符串)**。在Java里,这俩是截然不同的:

String a = null;
String b = "null";

System.out.println(a == null); // true
System.out.println(b == null); // false
System.out.println("null".equals(a)); // false
System.out.println("null".equals(b)); // true

是不是有点绕?但这恰恰是开发中最容易被忽略的点——尤其是和数据库、表单、JSON打交道的时候。

比如前端发请求的时候,有人可能会这样处理空值:

username = username || "null";

这种写法在意图上是想“空值补默认”,但问题是你补的这个默认值是“null”字符串,到了后端你还真别以为它是空的。然后你后端还用这名字去注册用户,完了,用户表里一堆“null”,一查全是同一个“人”,用户体验直接负分。

更可怕的是,数据库如果配了非空约束(NOT NULL),你以为防住了空数据,结果人家是个"null"字符串,一样插进去了。所以光靠数据库层面的非空约束,根本不保险。

那怎么办呢?一个简单靠谱的做法,就是对所有用户输入的数据都加一层预处理。比如统一写个工具类,对所有字符串做清洗:

publicstatic String sanitizeInput(String input){
if (input == null) returnnull;
    String trimmed = input.trim();
if ("null".equalsIgnoreCase(trimmed)) returnnull;
return trimmed;
}

你别看这个方法短小,真能救命。尤其是你跟前端对接、接外部API时,每一个输入字段都该先过一遍这个函数。就像洗手一样,你不能保证外面的世界干净,但你能确保自己不带病菌。

哦对了,别忘了数据库查询也会中招。如果你用类似下面这种方式去查:

User user = userRepository.findByUsername("null");

你以为查的是空用户名,其实人家就是叫“null”。这时候你查到数据了,逻辑就可能跑偏。解决办法还是那句老话:校验、再校验,对用户输入零容忍。

顺便说一句,那几个回帖提到的变种,比如nulI(小写L + 大写i)什么的,说实话更像是“撞库攻击”的骚操作——故意取一些肉眼看不出的混淆用户名。这在安全领域叫“字符伪装攻击”,不是我吓唬你,遇到这种情况,登录页上显示“欢迎你,nulI”你可能还以为是“null”,结果人家悄悄干了别人的活儿。

解决这个问题也不难,正则校验+黑名单机制:

if (username.matches("(?i)null|nulI|nuli|n1ll")) {
thrownew IllegalArgumentException("用户名非法");
}

再高级点的,可以用视觉相似字符检测,但这个就复杂了,要引入更强的安全策略和检测库。

说到这里,我得提醒下还喜欢搞“默认密码”的兄弟们,不要再用“123456”或者“password”这种密码了,也不要再让系统里默认写死密码是"********",这不是安全,这是自欺欺人,攻击者看到这种就像看到红布的公牛,直接就冲了上来。

所以,整篇帖子的搞笑外壳下,其实隐藏着几个我们每天都可能踩的雷:

  1. 字符串"null"和null空指针傻傻分不清
  2. 不规范输入未做预处理就直接存数据库
  3. 安全验证只靠数据库约束而不靠逻辑层控制
  4. 用户名或密码字段缺乏有效的合法性校验
  5. 对视觉字符伪装攻击完全没有防范意识

这些看似小事,但真的能让你debug到两点,甚至通宵。谁没因为个bug掉头发呢?

所以写这篇不是为了嘲笑谁,也不是危言耸听,而是真心建议各位兄弟姐妹们——认真对待用户输入,别让字符串"null"玩死你。

还有一个我想问一下,你们有没有取过什么更加牛逼(坑爹)的用户名??

Image