array(5) { ["chapterid"]=> string(8) "46603794" ["articleid"]=> string(7) "6827007" ["chaptername"]=> string(7) "第4章" ["content"]=> string(10586) "第4章 代码审查------------------------------------------ 代码审查,会议室302,参与的人不多,林深、小张、还有后端组的另外两个人,顾晚作为产品方旁听。,一张长桌,六把椅子,投影仪连着小张的笔记本。小张把玄机科技的SDK代码拉到屏幕上,从第一个文件开始讲,声音不大,语速均匀,偶尔点一下鼠标翻页。,手边放着一杯水,没有动过。,手里拿着一支笔,面前放着一个本子,偶尔记几个字,大部分时间只是听。---。,依次过了一遍:初始化配置、网络请求封装、数据序列化、错误处理、日志模块。每个模块他都看了代码,说了自己的判断,总体结论是:代码质量不错,注释完整,没有明显的安全漏洞,可以直接集成。"这个SDK写得挺规范的,"小张说,"比我们自己写的还干净。"。,也没有说话,只是看着屏幕。,这是SDK里最复杂的部分,代码量也最大。他快速过了一遍,说:"加密这块用的是AES-256-GCM,密钥派生用的是PBKDF2,都是标准算法,没问题。"。`generateSalt()`函数上停了一下。。
这个函数,用的是系统时间戳加上设备ID做种子,然后经过一次SHA-256。这个结构,他在三年前见过。不是作为漏洞见过,是作为一个刻意设计的特性见过。在"深海"任务里,这种盐值生成方式被用来做一件事:让特定的攻击者在知道设备ID的情况下,能够预测密钥,从而在不留痕迹的情况下解密数据。
这不是一个疏忽,这是一个设计。
他把这个念头压下去,用了不到一秒。
小张还在等他,"怎么了?"
"没问题,"林深说,"可以用。"
他的声音和平时一样,平静,没有任何停顿。
小张点了点头,"好,那这块就过了。"他准备翻到下一个文件。
顾晚在本子上写了什么,没有抬头。
林深把视线从屏幕上收回来,重新看向小张的笔记本。他刚才说的那句话,"没问题,可以用",是他在不到一秒里做出的决定。他可以说出来,可以指出那个函数的问题,可以让小张发邮件给玄机科技要求修复。但他没有。
他需要这个后门继续存在。
如果他现在把这个问题提出来,玄机科技那边会收到修复建议,他们可能会修复,可能会不修复,但无论如何,他们会知道有人注意到了这个函数。而他现在还不知道这个后门背后是谁,不知道这件事的全貌,不知道他现在的处境。在信息不足的情况下,暴露自己的判断,是一件危险的事情。
他把这个念头压下去,继续看屏幕。他现在需要的是更多的信息,而不是一个过早暴露的判断。
---
审查继续往下走。
小张翻过了加密模块,开始讲下一个文件,是SDK的会话管理模块。林深重新看向屏幕,表情和之前没有区别,平静,专注,偶尔点头。
但他的脑子里,还停在刚才那段代码上。
他刚才说的是实话,这是一个中危漏洞,实际利用难度不低。但他没有说的是另一件事:这个函数的结构,这种用时间戳加设备ID做种子的方式,他在三年前见过。不是作为漏洞见过,是作为一个刻意设计的特性见过。
在"深海"任务里,这种盐值生成方式被用来做一件事:让特定的攻击者在知道设备ID的情况下,能够预测密钥,从而在不留痕迹的情况下解密数据。
这不是一个疏忽,这是一个设计。
他当时没有参与这个模块的设计,但他知道这个设计的存在,因为他曾经被要求评估它的安全性,然后被告知"这是需求,不是漏洞"。他当时没有多问,因为那种任务里,你不问不该问的事情。
现在这个设计出现在玄机科技的SDK里,出现在一个要被集成进他们公司系统的商业产品里。
如果这个后门是真实的,那么任何集成了这个SDK的系统,在攻击者知道服务器实例ID的情况下,都可以被静默解密。
他把这个念头压下去,继续看屏幕。
小张在讲会话管理模块的token刷新逻辑,说得很详细,林深听着,偶尔回应一两个字。
顾晚抬起头,看了林深一眼,然后重新低下去。
---
审查结束的时候,是下午三点四十分。
小张总结了一下,说整体没有大问题,可以推进集成。大家收拾东西准备走,顾晚站起来,把本子合上,走到林深旁边。
"林工,"她说,"加密模块那块,你确认没问题?"
林深把椅子推回去,"没问题。"
"好,"顾晚说,"那我今天就推进联调。"
她停了一下,没有立刻走,"你对加密这块很熟。"
"看过一些资料。"林深说。
顾晚看了他一秒,"嗯。"她走了。
小张是最后一个收拾好的,站起来,拍了拍林深的肩膀,"今天审查挺顺的,比我预期快。"
"代码质量不错,"林深说,"没什么大问题。"
"还是你厉害,"小张说,"改天请你吃饭。"他拿着咖啡杯走了。
林深站在会议室里,等其他人都出去了,才走到投影仪旁边,把小张的笔记本屏幕看了最后一眼。
`generateSalt()`函数还在屏幕上。他盯着那段代码,把关键的几行在脑子里过了一遍,确认自己记住了,然后把笔记本合上,跟着走出去了。
走廊里,顾晚已经不见了。林深往工位方向走,经过茶水间,里面有人在倒水,没有注意到他。他走过去,没有停。
他在想一件事:如果这个后门是真实的,那么玄机科技的SDK被集成进多少个系统里?
他们公司是一个,但玄机科技的官网上说,主要客户是金融和政务行业。如果那些系统里也集成了这个SDK,如果攻击者已经在收集那些服务器的实例ID……
他把这个念头停下来。
他现在没有足够的信息,推断没有意义。他需要的是更多的数据,而不是在走廊里想象最坏的情况。
---
回到工位,他没有立刻打开电脑。
他先去了一趟茶水间,倒了一杯水,站在窗边喝完。窗外是公司楼下的停车场,下午的阳光斜着打过来,把车顶晒得发亮。他站了大概两分钟,没有想什么,只是站着。
然后他回到工位,坐下,打开电脑,打开浏览器,搜索了一个词:PBKDF2 salt generation timestamp vulnerability。
搜索结果出来了,有几篇安全研究的文章,有CVE数据库的条目,有Stack Overflow上的讨论。他快速扫了一遍,找到一篇2021年的安全研究报告,里面详细分析了一类使用时间戳作为盐值种子的实现方式,结论是:在攻击者能够获取设备标识符的情况下,这类实现存在可预测性漏洞,攻击窗口取决于时间戳的精度和设备ID的获取难度。
他把这篇报告的链接复制下来,保存在一个本地的文本文件里。
然后他又搜索了另一个词:玄机科技 SDK 安全漏洞。
没有结果。
他换了一个搜索词:XuanJi Tech SDK security。
还是没有结果。
这说明这个漏洞,或者说这个后门,目前没有被公开披露过。要么没有人发现,要么发现了但没有公开,要么知道的人选择了沉默。
他关掉浏览器,在桌上找到一张便利贴,写了三个字:可预测。然后把便利贴贴在显示器边框上,和其他几张便利贴放在一起,看起来和任何一个普通程序员的工位没有区别。
小张从茶水间回来,经过他的工位,瞥了一眼屏幕,"在写联调代码?"
"嗯。"林深说。
"今天审查完了,"小张说,"我整理一下会议纪要,下午发给大家。"
"好。"林深说。
小张回到自己的工位,打开电脑,开始做别的事情。
林深看着小张的背影,没有说话。
他在脑子里把今天的信息重新整理了一遍。
第一,玄机科技的SDK里有一个`generateSalt()`函数,结构和"深海"任务里的一个后门模块高度吻合。
第二,他没有提出这个问题,说了"没问题,可以用"。这意味着玄机科技那边不会收到任何修复建议,后门会继续存在。他需要这个后门继续存在,因为它是他目前掌握的唯一一条线索。
第三,他现在是这个项目的接口联调负责人,他会接触到SDK的完整集成过程,会知道哪些数据会经过这个加密模块,会知道服务器的部署方式。
如果有人想通过这个SDK收集信息,把他安排在这个项目上,是一个很合理的选择。他了解"深海"的代码,他能看出那些特征,他会知道这个SDK是什么。
但他不知道的是:这是在测试他,还是在利用他?
他从抽屉里拿出一张空白的草稿纸,拿起桌上的圆珠笔,开始写。
他写的是刚才那段`generateSalt()`函数的核心逻辑,不是完整的代码,只是结构:输入是什么,经过什么处理,输出是什么,关键的参数在哪里。他写得很快,不到两分钟,写完,看了一眼,然后在旁边空白的地方,开始写另一段。
第二段是从记忆里写出来的。
三年前,"深海"任务里,那个被设计成后门的盐值生成模块,他当时评估过,记住了核心结构。他把它写出来,写在第一段的旁边,两段代码并排放着。
他把笔放下,看着这两段代码。
结构几乎一样。输入参数的顺序不同,中间的哈希算法从SHA-1换成了SHA-256,但骨架是一样的。如果把第一段代码里的SHA-256换回SHA-1,再调整一下参数顺序,两段代码就是同一段代码。
像是同一棵树长出的两根枝。
他在草稿纸上盯着这两段代码看了很久,然后把草稿纸折起来,放进裤子口袋。
旁边小张坐回工位,打开电脑,开始整理今天的会议纪要。他打字的声音很轻,偶尔停下来想一下,然后继续打。
林深打开电脑,打开IDE,找到接口联调的项目,继续写代码。
他写的第一个函数,是调用玄机科技SDK的初始化接口。代码很简单,十行以内,他写完,测试,通过,提交。
然后他打开下一个文件,继续写。
口袋里的草稿纸,他没有再拿出来看。他不需要再看了,那两段代码,他已经记住了,不需要再看了。" ["create_time"]=> string(10) "1776413421" }