最近在搞二级域名分发系统,发现陈家洛在大佬论坛里面反映了一个 bug,在原帖12楼的回复

大致意思就是如果一个用户做了一个主机记录的A解析,那么其他用户也可以做同样记录名的不同A解析,以我的DNS举个例子,用户A添加了cs.zz.tn,解析方式是A记录,解析值是1.2.3.4,那么用户B可以添加同样的cs.zz.tn,解析方式也是A记录,但是解析值不能是1.2.3.4,可以是2.3.4.5。

这个问题我没复现成功,但是我发现的是,同一个用户,可以做同一个主机名的不同A记录很多次,并且域名的解析是生效的,因此可以判断出,在这里的逻辑是新增解析的时候,会判断是不是之前有的同样的主机名账号是不是与当前账号一致,如果一致,则可以添加同样主机名,如果不一致,则添加失败。于是我用Visual Studio查询了所有代码,找到了这个判断的代码位置。

从数据库查询可以得知,主机名的值是name,于是我将判断代码发送给ChatGPT,询问它这个代码中是否确认了name的唯一性,得到的答案如我所想,并没有直接确认唯一性,但是在新增记录的时候,校验了name值的唯一性,在新增记录的时候,uid和did与当前用户一致时,可以存在同样的主机名。

确认问题之后,我尝试让ChatGPT帮我修改一下代码,要求是无论did与uid是否与当前用户一致,只要存在了这个主机名的name,就返回错误结果。事实证明它确实帮我完成了。

代码修改如下,首先进入以下路径:网站目录/src/app/Http/Controllers/Home,需要修改该路径下的HomeController.php文件,注意,该路径下只有这一个文件。找到如下代码:

1
2
3
$ } elseif (!$id && DomainRecord::where('did', $data['did'])->where('name', $data['name'])->where('uid', '!=', Auth::id())->where('line_id', $data['line_id'])->first()) {
$result['message'] = '此主机记录已被使用';
}

替换成如下代码:

1
2
3
$ } elseif (!$id && DomainRecord::where('name', $data['name'])->first()) {
$result['message'] = '此主机记录已被使用';
}

但是正如ChatGPT在上面帮我审查代码时所说,这个只是修改了新增记录的时候,校验了主机名的唯一性,但是在更新的时候,并不会去校验,我复现了一下。

在用户A账号中,添加cs.zz.tn的域名,A记录指向1.2.3.4,其他用户均不能添加cs的主机记录。但是如果用户B一开始添加了cs2.zz.tn,A记录指向1.2.3.4是可以的,这个时候用户B去修改一下cs2的主机名,改成cs,是无法生效的的,因为跟用户A使用了同一个主机名,并且解析记录一致,但是他只要同时改一下解析值,比如A记录指向2.3.4.5是完全可以的,这个时候cs.zz.tn就在DNS上有了两条记录,均是A记录,分别指向1.2.3.4和2.3.4.5。

于是我继续让ChatGPT帮我加了一个在更新时校验主机记录的唯一性,目前主机记录唯一性的bug就算彻底完善了。

代码如下,还是这个文件,找到大概137行,if ($id)开头的,有个注释标注出来的更新,在这个注释行下面另起一行,输入以下代码

1
2
3
4
5
6
$ if ($id) {
if (!$record = DomainRecord::where('id', $id)->first()) {
$result['message'] = '记录不存在';
} elseif (DomainRecord::where('name', $data['name'])->where('id', '!=', $id)->first()) {
$result['message'] = '此主机记录已被使用';
} else {

往下找到大约155行,是【更新】判断到【添加】判断的之间,代码差不多是如下图的,就是在这开头的 } else {上面,敲个回车,然后在上面回车的那一行,输入一个 } 就行了。