方案探索过程
随着CVE-2020-5421的公布,一直使用Spring framwwork老版本的系统突然发现面临着窘境,Spring 开源社区公布的四个修复漏洞的版本,只是对针对仍在维护的分支的,在这几个分支上的版本可以通过顺滑升级解决问题,但对那些已经停止维护的分支比如3.1.x ,3.2.x..则需要使用者自己来解决这个问题。而做大幅度跨版本的升级一定会面临不可尽知的兼容性问题,在紧迫的限期交付补丁包的压力下,真不知道最终交付的是"安全补丁"还是""连环雷的引信"。
自己对在使用的版本进行对应修改虽然可以用简单的一句话轻飘飘的来概况:找到对应的修改,然后移植到自己用的版本上。但每一步的实现,都还需要付出沉重的努力。特别是在漏洞被公开后,负责安全的部门也只是根据公开信息落实责任,对该漏洞的详情也仅限于网络上的有限知识,在向这些专业人士咨询后也发现,对该问题只是简单通报,对再现和验证连可操作性的说明也没有,对可见的修改方案就更不要奢望了。在经过:忙乱,急躁,沉静,深思后,我们规避了最激进的方案,以尽量小的修改来解决这个问题,为此也分成两个方案,一个是无跨度,即在当前版本(V3.1.1)上进行修改;一个是最小跨度,即找到一个最近版本的较解决完善的版本,在上面做修改, 经查看版本更新历史发现在v3.2.15上已经修复CVE-2015-5211, 只要再修补CVE-2020-5421即可,选择把它作为了这个最接近版本来用。具体的工作情况在下面做了记叙,以防遗忘,也为了给解决类似问题一点参考。
方案一:
构建3.1.1
这个工作也不是一帆风顺,限于环境的差异及网络的不通畅,也消耗了超出预料的时间。这个过程在单独的过程中做了记录,参见对Spring framwrok 3.1.1 进行构建
探索修改内容
在构建的同时还在通过代码提交历史及阅读代码定位关于CVE-2015-5211和CVE-2020-5421两次修改相关的提交,这个过程也是"拔起萝卜带起泥",本想尽量留用社区的修改代码,但确实版本的变化涉及了功能的增加,而修补又是在功能添加的基础上的,大有无限蔓延的架势。如果不做取舍也就陷入了泥潭,难免要大动干戈,看到这个结果也几临崩溃到要放弃。好在及时的扭转念头,做了"断舍离",终于将修改内容圈定在了闭合的范围内。
修改 CVE-2015-5211
为避免在文中出现太多代码,请参见补丁提交记录Protect against RFD exploits
修改 CVE-2015-5211
请参考补丁提交记录Avoid unnecessary parsing of path params
形成的的补丁代码
最终要做的修改在这里已经叙述过了CVE-2020-5421 的修复方法说明,本文只侧重整体过程的记叙和总结,最终结果在这里了,可以结合下文查看和使用代码补丁文件。
在修改后提交记录上生成patch
git format-patch -1 <commitId>
如果要使用该patch, 可以下载patch 文件后可在基于3.1.1.RELEASE 标签建立的分支打上补丁,过程如下
# 基于标签v3.1.1.RELEASE 建立分支
git branch v3.1.1.clone v3.1.1.RELEASE
# 切换分支
git checkout v3.1.1.clone
# 在新建分支上打上补丁
git apply <patchfile>
# 构建或继续进行修改
...
方案二
这个方案里,最担心的是版本的兼容性问题,在未做任何修改的情况下把升级为3.2.15进行测试,果然很快遇到了问题。因为我们对spring框架做过扩展,对rest的相关的json序列化进行过处理,而3.2.x和3.1.x在对http 消息转换的处理上 存在差别,导致出现了异常。虽然定位到了问题,但是否还有类似问题?是否能在非常有限时间里发现和解决,这显然是有很大的不确定性。
随想
随着方案一的修改的完成,最终选用了的方案一作为本次补丁的应对之策。但这应该认识到这只限于对本次的问题在有限的时间内应对是最优的方法,并不是系统性的最优,出现开始描述的窘境的原因是因为日积月累欠下的"技术债",既然系统还在生命周期内,尚未有明确的下线日期,为避免这样的窘境,就应该在日常的工作中有组件升级的安排。这正如对你的爱车的保养,做保养时看似多余,但如果从不做养护,到问题发生时可能的后果就是你不能承受的。
回头看时,都是很简单的事情,直接按照以上步骤进行修改,可能在两个小时内就能完成。但正如软件生产的成本和传播成本的差异,复制粘贴很快就能完成,走直路也永远都是快乐的,但如果你未经过对问题的一头雾水,对多个方案的思考和对比,对每个步骤的不确定性的体验,你不会知道,所谓的直路都是经历过的人给你做过路标才是可能有的。
假如类似问题再次来临,还是要遵守事情的规律,做到不急不燥,同时大胆心细,在对问题做深入分析的基础上完成修改,且对形成问题的复现及检测的有效方法要充分重视,这是开发方与安全检测方必须达成一致后才能关闭问题的核心点。
当然,作为重点最后重复一遍:从长久来看,及时的技术升级是避免出现窘境的根本,特别是对于对技术进行集中管控的组织,业务应用开发者使用了组织内定制和扩展后的开源组件,集中管控方要主动推动业务项目组的组件升级,这也是集中管控的重要作用。