关于静态应用安全测试SAST的一些工具的autofix的实现,可以参考https://blog.csdn.net/jimmyleeee/article/details/136356545。本篇文章主要是针对如果真正autofix需要解决哪些有挑战的问题进行探讨。
要实现SAST的自动修复,需要解决的就是误报的问题。如果一个被SAST检测出的问题不是真正的问题,那就没有修复的必要。针对误报进行修复,反而可能导致修复带出新的问题。即使修复没有带来新的问题,那么,修复也是无用的。目前市场上很多的SAST的产品而言,如果在使用默认的规则集进行扫描的前提下,误报还是很高的(虽然一些厂家号称误报很低,那是在一些公开的测试的基准项目的基础上测试的,已经进行了针对性的优化)。如果某个公司买了一套产品,在没有规则定制的情况下,误报会很高。在这种高误报的情况下,即使有自动修复,估计也没有人敢去启用它。在误报没有很好地解决的情况下,只会带来更多地负担。因为每次的修复,无论是否会带来新的问题,都需要进行测试和验证,以防万一。
第二、如何找到正确的修复位置
每种语言都忽悠很多框架来实现某些统一的基础功能,同一种应用,又可以分成前端和后端。每种框架结构都可能会提供针对某一个问题的解决方案,在哪一个框架里修复会更好呢?如果可以在前端修复,也可以在后端修复,如何决策在前端修复?还是在后端修复?
举个例子,XSS问题,前端架构像Handlebars会提供针对XSS的解决方案。例如:输出的时候使用三个大括号,就是原始内容输出,{{{data}}},如果使用两个大括号输出,{{data}}就会进行HTML编码。同时,在后台如果已经对输出的data进行了编码,就可以使用三个大括号也能保证安全;如果使用后台没有对data进行任何处理直接输出,就会必须要使用两个大括号输出才能保证不受XSS攻击。对于SAST而言,如果将某个输出和后台的代码的输出对应起来是一个很大地挑战。如何判断在后端是否做了编码?就更难了。 对于自动修复而言,如果在以上基础上结合起来,决定在哪里做修复呢?同样一个架构,也可能会存在修复方案的不同,例如:针对Spring的架构,有的产品可能在Controller修复,有的产品可能在Service层;有的通过Filter来修复,有的通过interception修复。甚至有的公司有专门的解决安全问题的架构,如果让工具识别出这种修复方案?
第三、如何提供有效的解决方案并修改代码?
根据漏洞类型的不同,解决方案的提供的难易程度也不一样。同样一种漏洞类型,也可能会需要不同的解决方案。
例如:以下示例代码:
- @Insert({"insert into ${tableName} values (${taskid},now())"1)
-
- int saveTask(@Param("tableName”) string tableName, @param("taskid") string taskid);
虽然tableName和taskid都是类似的参数,也同样会产生SQL注入的问题,但是两个参数的解决方案是不一样的。针对taskid,可以直接通过以下代码避免SQL 注入:
- @Insert({"insert into ${tableName} values (#{taskid},now())"1)
-
- int saveTask(@Param("tableName”) string tableName, @param("taskid") string taskid);
就是将$符号用#符号替换即可,框架会处理剩下的事情。
但是,对于tableName如果这么处理就会出错,需要创建一个验证tableName的函数,通过白名单或者正则表达式来验证tableName的值是否含有一些异常的字符。
另外一个例子就是写在代码的硬编码的密码问题,即使能够100%识别此类问题,如何根据产品的架构提供一个安全的解决方案呢?可能有的人会说,提取出来放在配置文件里,然后再生成代码从配置文件里获取不就可以了吗?其实,写在配置文件和写在代码里的密码都是硬编码密码,都是不安全的。需要有一套能够保证密码安全而且又可以动态更新的密码才是安全的密码,关于硬编码的密码的问题,具体可以参考:https://blog.csdn.net/jimmyleeee/article/details/132078032。
即使工具对扫描发现的漏洞进行了自动修复,如何保证修复是正确的?不排除有的修复方案是不全面的,甚至可能有的修复方案就是不正确的。
由以上两个例子可以看出,如果要实现检测的漏洞代码的自动修复还是很有挑战的。
第四、被自动修复的代码会影响哪些测试代码?如何处理相关的测试代码?
在代码被修复之后,如果没有影响内部逻辑,就不会影响到相关的测试代码;如果影响内部的逻辑导致输入的内容和输出的值有变动时,如何通过改动的代码去找到相关的测试代码,并且针对性地修改测试代码保证测试用例可以正确地通过?
更为麻烦的是自动化测试用例,产品的自动化测试用例是使用专门的语言由专门的人员编写和维护的,是完全独立的,根本不会和现有的代码一起扫描。如何能够找到被修改代码所影响的自动化测试用例并且根据修复的代码来正确地修改测试用例?或者,根据已有的用例判断是否对修改的代码而言有遗漏的用例需要补充完整的?
代码被修改是第一步,保证代码能够通过测试是更重要的一个步,如果这一步不能够自动化,那就需要人工根据修复的代码来查找影响的测试代码和测试用例,否则,在CI/CD流程中,可能会因为测试用例不过而阻塞整个产品的发布。
第五、自动修复的代码如何保证源代码在修复之后的语法和语义的正确性
自动修复代码是机器生成的代码,和原来的程序员的代码结合在一起时,如何保证机器生成的代码能够和人写的代码无缝地结合在一起?是否会产生语法或者语义错误?
自动修复的挑战分析了之后,目前而言,能够实现通过Guide或者用户的Click来实现指导性地帮助开发整争取地修复安全问题已经算是很好的了。现阶段而言,SAST即使提供了自动修复的功能,也不能放心地将修复工作完全交给工具,还是需要人的参与审查才行。虽然自动修复的功能不能彻底解决问题,但是,它可以通过批量处理类似的问题来协助开发人员提高解决安全问题的效率。
当面对一个产品宣传实现了自动修复之后,可以尝试从以上几个挑战的方面去测试一下自动修复的效果。
随着AI的不断发展,相信有一天AI能够识别代码中的漏洞实现自动修复的功能,将开发者从安全的苦恼中解脱出来,期待这一天尽快到来!