在进行Fortify SCA扫描的时候,漏洞并不是立刻被寻找的,在这之前,代码需要经历一个很关键的翻译阶段,很多时候项目出现报错,原因既不在于规则包,也不在于扫描策略,而是代码没被Fortify SCA成功读取进去,关于Fortify SCA翻译阶段怎么配置,以及Fortify SCA翻译日志报错怎么定位,主要需要紧盯着三件事情,也就是构建ID要对得上,依赖路径不能缺失,还有日志里写出的到底是解析错误还是环境错误。
一、Fortify SCA翻译阶段怎么配置
翻译阶段可以理解成“让Fortify SCA先认识项目代码”。官方命令结构一般是sourceanalyzer -b
1、先清理旧的构建会话
在重新开始翻译之前,应该先执行【sourceanalyzer -b项目ID -clean】这个命令。
这地方是一个容易被漏掉的步骤,在项目更换了分支、依赖发生更新、或者扫描脚本被改动过的时候,旧的中间文件往往还会残留在那里,要是旧的记录没被清理干净,后面暴露出来的报错,可能就不是由当前的代码所引起的,通常会建议一个项目固定去使用一个build ID,但是在每次正式开展扫描之前,都得先执行一次清理,免得旧数据对后面的判断产生干扰。
2、根据项目语言选择翻译方式
对于Java项目,源码可以直接被翻译,或者利用Maven、Gradle、javac等构建命令把翻译过程包裹起来;C/C++项目在操作时,往往对真实的编译过程依赖性更强;至于JavaScript、TypeScript、Python、PHP、Ruby这些动态语言,必须要多加注意,得把相关的源文件一次性都放到翻译里面去,官方的说明文档中也特意提到了,这类动态语言并不支持在后面往同一个build ID里面去不停地追加新文件。
3、把依赖和编码配置补全
结合着【-cp】、【-sourcepath】、【-encoding】这几个参数,需要对依赖和源码的编码进行检查。
在翻译失败的案例中,“代码明明能编译,却被Fortify SCA翻译得不完整”是经常发生的,这往往是因为脚本里面把jar包写漏了、把源码路径写少了,或者源码根本不是默认的编码格式,其中的-encoding参数是专门用来指定源码文件编码的,Fortify SCA会在翻译阶段读取源码时把这个编码信息记录下来。
在中文的项目里面,若是日志中出现了乱码、字符串解析错误、或者是注释旁边报错,可以尝试先用这个办法:
sourceanalyzer -b MyProject -encoding UTF-8...
要是面对的是使用GBK的老项目,那也不能随便地写成UTF-8,必须要让设置和仓库实际的编码保持一致。
二、Fortify SCA翻译日志报错怎么定位
在看翻译日志的时候,视线不能只落在最后的一行上,最后一行往往只写着“翻译失败”或者“去看日志文件”这种提示,真正有用的内容其实都在前面藏着呢,特别是头一个出现的ERROR、头一个没法解析的import、或者是头一个找不到的编译器和依赖路径。
1、先打开详细日志
可以在翻译命令里面把【-logfile】和【-debug-verbose】这两个参数加进去,然后让报错再复现一次。
通过-logfile,Fortify SCA生成的日志文件就可以被指定出来,而-debug-verbose所记录的信息会比一般的debug还要多,尤其是在面对解析错误的时候,这个参数很有用。
可以先按照下面这个样子去跑一次:
sourceanalyzer -b MyProject -logfile fortify_translate.log -debug -verbose...
如果这个过程是在CI环境里执行的,日志文件最好能固定地输出到构建产物目录中去,不能只靠控制台里不断滚动的日志,要不然任务一旦失败,开发人员在回头排查细节的时候就会变得很费劲。
2、查看翻译阶段警告
运行【sourceanalyzer -b项目ID-show-build -warnings】后,翻译阶段里产生的警告和错误就可以被看见了。
Fortify SCA提供了一个-show-build-warnings命令,翻译阶段里出现的warning和error都能被它列出来;同时利用-show-files,某个build ID里面到底装了哪些文件也能被看清楚。
进行第一轮问题判断的时候,这两个命令比较合适:
sourceanalyzer -b MyProject -show-build-warnings
sourceanalyzer -b MyProject -show-files
如果在-show-files里面发现文件的数量明显变少了,那就说明翻译的范围没有配对;如果文件都在,但是warning特别多,那就要进一步去看看,到底是依赖丢了,还是语法解析上出了岔子。
3、按错误类型分开处理
要是日志里面显示了【Unable to resolve type】、【Unable to locate import】、【Unable to resolve symbol】这些字眼,应该把检查依赖路径作为优先要做的事。
在Java项目里,这类警告出现的原因,通常都和缺少jar包、缺少class文件、或者classpath写得不全有关系,官方的文档也把这种warning算作是缺少资源,或者依赖文件没有被写完整这一类的问题。
三、翻译阶段常见问题怎样提前减少
很多在Fortify SCA翻译阶段出现的问题,其实并不是扫描当天才冒出来的,而是脚本在刚开始写的时候,没有顺着项目的结构去设计好,特别是遇到多语言的仓库、前后端混在一起的项目、旧的Java项目、或者是C/C++跨平台的项目,更得提前把翻译脚本写得死板、稳定一点。
1、给不同模块拆分清楚build ID
要是多模块的项目,不要把所有的内容塞在一个build ID里面。
如果前端、后端、批处理、还有数据库脚本都放在一个仓库里,可以按照模块分别去设置不同的build ID,然后再根据各自的需要分开扫描,这么做带来的好处就是日志会更清晰,某个模块要是翻译失败了,不至于把所有的信息都搅和在一起,后面在排查的时候,也能很快地看出来问题到底是出在Java后端,还是出在前端的TypeScript部分。
2、让扫描脚本尽量贴近真实构建
项目在平时是怎么被编译的,在Fortify SCA的翻译阶段,就应该尽量贴着那个一模一样的流程去走。
千万别为了图省事,就随便写一个通配符去扫整个目录,对于那些编译型的语言来说,真实的构建过程是要去处理依赖、宏定义、生成文件以及编译参数的,这些信息全都会对翻译的结果产生动摇,脚本如果越脱离真实的构建,日志里就越容易冒出一堆看起来乱七八糟、实际上全是因为缺少构建上下文而引起的问题。
3、保留每次失败的日志和命令
应当把【执行命令】、【fortify_translate.log】、还有【show-build-warnings的输出】放在一起进行保存。
光留着一份最终的FPR文件是不够用的,在对翻译问题进行排查的时候,当时使用的命令和生成的日志其实更有价值,尤其是在CI环境里面,环境变量、工作目录、依赖缓存、还有JDK版本随时都会变,下一次要是又失败了,手里如果没有历史日志,就只能坐在那里重新瞎猜了。
总结
关于Fortify SCA翻译阶段怎么配置,要想办法让Fortify SCA按照对的build ID、对的源码范围、以及对的依赖路径去把项目给读懂;至于Fortify SCA翻译日志报错怎么定位,应当先去看看-show-build-warnings,再去看看-show-files,在必要的时候,还要配合着-logfile和-debug-verbose去重新折腾一次,只有把翻译阶段给走稳当了,后面拿到的扫描结果才能算数;要是翻译阶段缺了文件、漏了依赖、还留着一堆的warning,那么后面就算弄出来的报告再好看,多半也只是“漏扫漏得很干净”而已。