寻找适合编写静态分析规则的语言

news/2024/7/8 3:46:49/文章来源:https://www.cnblogs.com/huaweiyun/p/18285073

本文分享自华为云社区《寻找适合编写静态分析规则的语言》,作者:Uncle_Tom。

1. 程序静态分析的作用

程序的静态分析是一种在不运行程序的情况下,通过分析程序代码来发现潜在的错误、安全漏洞、性能问题以及不符合编码规范的情况的技术。
程序的静态分析在现代软件安全中扮演着至关重要的角色。以下是静态分析在软件安全中的一些关键作用:

代码质量保证:

静态分析有助于确保代码符合安全编码标准和最佳实践,从而提高代码的质量和安全性。

参考:代码的安全检视

合规性检查:

许多行业标准和法规要求对软件进行安全合规性检查。静态分析工具可以帮助组织确保其软件产品符合这些标准和法规要求。

参考:一图看懂软件缺陷检查涉及的内容

漏洞检测:

静态分析工具可以在代码编写阶段检测潜在的安全漏洞,如SQL注入、跨站脚本攻击(XSS)、缓冲区溢出等。

参考:2023年最具威胁的25种安全漏洞(CWE TOP 25)

减少开发成本:

通过在开发早期阶段发现问题,静态分析可以减少后期修复的成本和时间,因为后期修复通常成本更高。

参考:构建DevSecOps中的代码三层防护体系

2. 静态分析工具的业务痛点

随着现在工程项目的代码量越来越大,同时开发框架的快速迭代和出现。静态分析工具所需要覆盖的场景也随之快速的增加,但静态分析工具所提供的是通用的检查能力,以及静态分析工具有限的迭代速度,无法满足客户不断出现的各种差异化需求。

目前静态分析工具的主要痛点:

2.1. 无法开发自定义规则

大多数静态分析工具由于设计之初多是为了解决特定的编码问题,所以没有考虑到后期的扩展和由用户完成规则的开发。如果需要提供自定义开发能力,需要从架构上重新设计,或者因为检查效率的问题,无法提供通用的检查配置和自定义能力。这将导致无法快速提供客户特定的需求的问题检查。用户只能通过需求反馈的方式,等待工具下个版本的发布,需要的闭环周期很长。

2.2. 对误报和漏报的规则无法快速修改

静态分析工具由于是对代码的静态分析,输入存在不确定性,这些不确定性导致工具在分析策略在上近似(Over-approximation)、下近似(Under-approximation)以及检查效率三者之间寻求某种平衡,这三个因素互相影响、互相制约。

  • 上近似是指分析工具可能将一些实际上不会发生的程序行为错误地识别为可能发生的。换句话说,它可能导致分析结果过于宽泛,将一些安全的状态或行为错误地标记为不安全的。这也就导致了误报(false positives),即错误地将安全的代码标记为有问题。
  • 下近似是指分析工具可能未能识别出实际上会发生的程序行为。这意味着分析结果可能过于保守,遗漏了一些潜在的问题。这就导致了漏报(false negatives),即未能发现实际存在的安全问题或错误。
  • 效率是所有使用者一直追求的因素,快了还想快。但哪里有又想马儿跑得快,又想马儿不吃草的好事情。

由于这些原因,静态分析工具通常提供的是一种通用的检查规则,往往不能覆盖特定的场景,或覆盖场景不适合特定用户的使用条件,这也造成检查工具无法避免误报和漏报。比如说:从文件读对有的用户是危险,但对有的用户是安全的,工具无法识别用户读文件的实际场景,只能将所有从文件读设置为危险的。如果用户无法快速对工具规则进行修改,就会被检查结果中的误报或漏报造成困扰。

2.3. 开发自定义规则有一定的难度

分析引擎提供的自定义开发包,但也需要自定义规则的开发人员掌握静态分析的相关技术,用户上手的难度较大。且由于引擎对API的封装能力,对外提供的检查能力有限,在很大程度上限制了用户自定义规则的实现能力。

基于这些痛点,需要寻找一种适合编写静态分析规则的语言,来降低自定义规则的难度,使用户能够直接开发满足自己需求的规则,用户可以自己在很大程度上来控制和解决误报和漏报。

那么什么才是适合用户的编写静态分析规则的语言呢?

3. 寻找适合编写静态分析规则的语言

为了寻找适合用户的编写静态分析规则的语言,我们来看下我们常见的两种编程范式:声明式语言(Declarative Language)和命令式语言(Imperative Language)。这两者语言在如何描述程序行为和解决问题的方法上存在根本差异, 但同时各有优势和适用场景, 许多现代编程语言支持这两种范式, 允许程序员根据具体问题选择最合适的方法。

具体来看一个声明式语言和命令式语言对问题的不同解决方式。

问题:

从一个人群中挑出成年人;

具体条件:

选出的人年龄大于等于 18 岁。

命令式语言 – Java 语言

public List<Person> selectAdults(List<Person> persons){List<Person> result = new ArrayList<>(); for (Person person : persons) {if (person.getAge() >= 18) {result.add(person); }}return result; 
} 
声明式语言 – SQL 语言
SELECT * FROM Persons WHERE Age >= 18;

从这个例子可以看出来,声明式语言更适合用户的使用,这也是为什么 SQL 语言在短时间内能够迅速的被推广和使用。

声明式语言的特点,也正是我们正在寻找的适合编写静态分析规则的语言。用户只需要关注:“做什么”(What to do),即描述期望的结果或目标状态,而不指定如何达到这个结果的具体步骤或过程。

我们也可以把这个检查语言称为一种领域特定语言(Domain Specific Language,DSL),为特定领域或问题域定制的语言,专注于解决特定类型的问题。这个语言只专注于 – 编写程序静态分析的规则。

这里没有直接使用自然语言,主要是自然语言存在表述上的差异和描述的准确性的问题。当然随着大模型的越来越成熟,直接通过自然语言完成规则的编写,也离我们越来越近了。但不管怎样,在识别到检查条件后,还是需要有一个引擎将这些约束条件转换成具体查询的程序语言,完成问题代码的搜索,这就像 SQL 语言负责描述条件,还需要一个 SQL 的查询引擎,完成 SQL 语言的解析和实施查询。

4. DSL 在程序静态分析中的应用举例

4.1. 编写检查规则

检查问题:

  • 生产环境中不应该有调试代码。

问题检查条件:

  • 查找所有函数声明
  • 并且(And):函数名以"debug"开头
  • 并且(And):函数只有一个参数
  • 并且(And):参数类型为"java.util.List"
问题代码样例
package com.dsl;import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;import java.util.List;/*** 检查问题:生产环境中不应该有调试代码。* 问题检查条件:* - 查找所有函数声明;* - 并且(And):函数名以"debug"开头;* - 并且(And):函数只有一个参数;* - 并且(And):参数类型为"java.util.List"。*/
public class CheckDebug {private static final Logger LOG = LogManager.getLogger(CheckDebug.class);// 应检查出的问题函数public void debugFunction(List<String> msgs) {for (String msg : msgs) {LOG.error("print debug info: {}", msg);}}
}

编写检查规则

DSL 写的检查规则

/*** 检查问题:生产环境中不应该有调试代码。* 问题检查条件:* - 查找所有函数声明;* - 并且(And):函数名以"debug"开头;* - 并且(And):函数只有一个参数;* - 并且(And):参数类型为"java.util.List"。*/functionDeclaration fd whereand(fd.name startWith "debug",fd.parameters.size() == 1,fd.parameters[0].type.name == "java.util.List");

4.1.1. 规则的解读

程序是由空格分隔的字符串组成的序列。在程序分析中,这一个个的字符串被称为"token",是源代码中的最小语法单位,是构成编程语言语法的基本元素。

Token可以分为多种类型,常见的有关键字(如if、while)、标识符(变量名、函数名)、字面量(如数字、字符串)、运算符(如+、-、*、/)、分隔符(如逗号,、分号;)等。

程序在编译过程中,词法分析器(Lexer)读取源代码并将其分解成一系列的token。语法分析器(Parser)会使用这些 token 来构建一个抽象语法树(Abstract Syntax Tree, AST),这个树结构表示了代码的语法结构。这个时候每个 token 也可以称为抽象语法树的节点,树上某个节点的分支就是这个节点的子节点。每个节点都会有节点类型、属性、值。

下面来描述下规则中使用的 DSL 和需求之间的对应关系。

节点类型、属性、值

在规则中,需要查找的是函数声明。这里使用:functionDeclaration 为代码的函数声明节点。在这个节点下有许多的属性,可以通过“.”的方式获取这些属性。

例如函数节点有:函数名(name)、函数的参数(parameters)等子节点。同时每个属性有自己的类型,以及值。例如:函数名(name)为字符串类型,函数的参数(parameters)一个集合类型;

别名

在编写规则时,定义别名可以显著简化规则编写。在遇到复合条件查询时,建议定义别名,方便后面的使用。

例如:函数声明(functionDeclaration)的别名 “fd”,这样后面可以使用 “fd” 方便了后面对这个函数声明的使用;

集合

函数的参数(parameters)就是一个集合,里面可能会存在 0-n 个参数。对于集合类的节点,可以通过指定集合的索引值得到集合下的子节点。

例如:参数的第一个参数,可以表示为:Parameters[0]。 同样通过 “.” 得到这个参数的其他类型或属性;

内置函数

规则中使用了内置字符串函数。

例如:判断字符串以指定字符串开始的函数,startWith(“debug”),表示判断字符串以 “debug” 开始的字符串;

运算符和条件表达式

规则中的 “==” 是运算符,表示等于。通过运算符将代码的节点类型、属性和具体的值联系在了一起,构成了条件表达式。由此构成了规则需要的条件判断,适配我们期望的约束条件。

条件的组合

通常一个规则需要多个约束或限制条件构成。这里通过并且(and)完成了三个子条件组成的复合逻辑条件表达式。

结论

  • 通过这个案例我们可以看到,这个 DSL 语言非常接近我们的期望的需求表达式;
  • 用户可以通过 DSL 语言快速开发满足需要检查的问题;
  • 用户可以更多的关注如何描述需要检查的问题,而不需要关注工具是如何的实现。

4.2. 替换已有工具规则,并增加检查条件

4.2.1. 实现原有检查规则

原有检测问题:

  • 继承 java.util.TimerTask 类重写 run 方法,run 方法的实现要有 try-catch 保护。

检查的条件:

  • 查找类继承自 java.util.TimerTask
  • 并且(and):重写了 run 方法;
  • 并且(and):run 方法中没有 try-catch。
问题代码样例
package com.dsl;import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;import java.util.TimerTask;/*** 检查问题:继承 java.util.TimerTask 类重写 run 方法,run 方法的实现要有 try-catch 保护。* 问题检查条件:* - 查找类继承自 java.util.TimerTask;* - 并且(and):重写了 run 方法;* - 并且(and):run 方法中没有 try-catch。*/
public class CheckTimerTask extends TimerTask {private static final Logger LOG = LogManager.getLogger(CheckTimerTask.class);// 应检查出的问题函数
    @Overridepublic void run() {LOG.info("do some thing");}
}

编写检查规则


DSL 写的检查规则

/*** 检查问题:继承 java.util.TimerTask 类重写 run 方法,run 方法的实现要有 try-catch 保护。* 问题检查条件:* - 查找类继承自 java.util.TimerTask;* - 并且(and):重写了 run 方法;* - 并且(and):run 方法中没有 try-catch。*/
functionDeclaration fd whereand(fd.enclosingClass.superTypes contain parType whereparType.name == "java.util.TimerTask",fd.name == "run",fd notContain exceptionBlock);

4.2.2. 增加检查条件

基于上面一个例子,用户在使用时发现除了需要有异常捕捉之外,还需要记录错误或警告信息。由此需要对原来的规则进行修改,增加新的约束条件。

检查问题:

  • 继承 java.util.TimerTask 类重写 run 方法,run 方法的实现要有 try-catch 保护。
  • 在异常处理块中,需要有信息处理的函数: error 或 warn。

问题检查条件:

  • 查找类继承自 java.util.TimerTask;
  • 并且(and):重写了 run 方法;
  • 并且(and):run 方法中没有 try-catch。
  • 或者(or): run 方法中有异常处理块;
    • 并且(and): 异常处理块中有函数调用;
    • 并且(and):函数名为:error 或 warn。
问题代码样例
package com.dsl;import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;import java.util.TimerTask;/*** 检查问题:* - 继承 java.util.TimerTask 类重写 run 方法,run 方法的实现要有 try-catch 保护。* - 在异常处理块中,需要有信息处理的函数: error 或 warn。* 问题检查条件:* - 查找类继承自 java.util.TimerTask;* - 并且(and):重写了 run 方法;* - 并且(and):run 方法中没有 try-catch。* - 或者(or): run 方法中有异常处理块;*  - 并且(and): 异常处理块中有函数调用;*  - 并且(and):函数名为:error 或 warn。*/
public class CheckTimerTaskEnhance extends TimerTask {private static final Logger LOG = LogManager.getLogger(CheckTimerTaskEnhance.class);// 应检查出的问题函数
    @Overridepublic void run() {try {LOG.info("do some thing");} catch (Exception e) {LOG.info("do some thing");}        }
}

编写检查规则

DSL 写的检查规则

/*** 检查问题:* - 继承 java.util.TimerTask 类重写 run 方法,run 方法的实现要有 try-catch 保护。* - 在异常处理块中,需要有信息处理的函数: error 或 warn。* 问题检查条件:* - 查找类继承自 java.util.TimerTask;* - 并且(and):重写了 run 方法;* - 并且(and):run 方法中没有 try-catch。* - 或者(or): run 方法中有异常处理块;*  - 并且(and): 异常处理块中有函数调用;*  - 并且(and):函数名为:error 或 warn。*/
functionDeclaration fd whereand(fd.enclosingClass.superTypes contain parType whereparType.name == "java.util.TimerTask",fd.name == "run",or(fd notContain exceptionBlock,fd contain exceptionBlock eb whereeb contain functionCall fc wherefc.name notMatch "error|warn"));
结论
  • 通过这个案例,我们可以看到DSL 可以快速的替换现有工具已有的检查;
  • 并可以根据需求增加更多的检查条件,以增加对特殊场景的覆盖,从而减低规则的漏报率,同时也可以通过这个方式,降低工具的误报率,提升规则的检查的准确率。

5. 结论

通过上面两个案例,我们可以看到这个编写自定义规则的 DSL 语言,能够:
  • 实现规则的编写;
  • 实现规则的改进,降低误报率和漏报率;
  • 降低了检查规则的开发难度。
欢迎大家试用这个插件,并给出反馈意见。
  • 在 vscode 插件中查询:codenavi 添加插件即可。

点击关注,第一时间了解华为云新鲜技术~

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/738608.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用JAVA调用配方单保存接口更新数据失败, 使用了SaveParam参数

问题原因是SaveParam参数使用错误 传入json只能是model里的单据数据参数, model之外的参数是靠SaveParam的实例去设置, 金蝶的demo里也是很明显的, 如下图

博客的部署方法论

博客写完后,当然是要发布到网络上的。如果想要部署到服务器上,则需编译构建成静态文件,然后将其上传到服务器上的路径(该路径由我们自己决定),然后在 web 服务器(Nginx 等)上配置访问路径即可10.部署 博客写完后,当然是要发布到网络上的。如果想要部署到服务器上,则需…

安全帽佩戴检测系统

安全帽佩戴检测算法是高危作业环境中不可或缺的环节。传统依靠人工监管的方式存在效率低下、管理范围有 限、时效性差、无法全场监测等诸多缺陷,因此基于图像视觉的安全帽佩戴检测算法逐渐成为企业实施管理的主要手段。近年来,随着工业4.0概念的提出和深度学习等 高新技术的发…

基于 .net core 8.0 的 swagger 文档优化分享-根据命名空间分组显示

之前也分享过 Swashbuckle.AspNetCore 的使用,不过版本比较老了,本次演示用的示例版本为 .net core 8.0,从安装使用开始,到根据命名空间分组显示,十分的有用前言公司项目是是微服务项目,网关是手撸的一个.net core webapi 项目,使用 refit 封装了 20+ 服务 SDK,在网关中…

安全帽佩戴检测算法

安全帽佩戴检测算法是铁路工程施工人员安全管理中的重点和难点,它对检测算法的准确 率与检测速度都有较高的要求。本文提出一种基于神经网络架构搜索的安全帽佩戴检测算法 NAS-YOLO。该神经网络架构由上、下行操作单元组成,采用二进制门策略对网络架构进行更 新,通过数据驱动…

人员跌倒识别检测算法

人员跌倒识别检测算法是基于视频的检测方法,通过对目标人体监测,当目标人体出现突然倒地行为时,自动监测并触发报警。 人员跌倒识别检测算法基于计算机识别技术,配合现场摄像头,自动识别如地铁手扶梯/楼梯、老幼活动区等公共场所人员摔倒行为,准确率高于90%,及时救援,提…

学校视频监控系统

学校视频监控系统可以借助分布在学校各处的传统监控摄像头对学校的日常生活进行实时安防监控,学校视频监控系统保障学校的日常安全以及对学生的人身财产安全进行及时预警。帮助学校在技术日益进步的当下,提升对学校的安防监控能力和日常管理的效率,使得学校在安防监控这方面…

读人工智能全传03分治策略

读人工智能全传03分治策略1. 黄金年代 1.1. 图灵在他发表的论文《计算机器与智能》中介绍了图灵测试,为人工智能学科迈出第一步做出了重大贡献 1.2. 美国在第二次世界大战后几十年里计算机技术发展的特色,也是美国在未来60年内确立人工智能领域国际领先地位的核心 1.3. 1955年…

[6.27~7.4 做题记录]

[6.27~7.4 做题记录] 暑假集训,记录一些有意义 (多半无意义) 题目,不定时更新。 概率期望DP OSU! 考虑设 \(E_i\) 为到第 \(i\) 次操作时的期望分数。我们发现从 \(x^3\) 到 \((x+1)^3\) 将加上 \(3x^2+3x+1\),我们考虑 \(x\) 和 \(x^2\) 的期望: \[x1_i=(x1_{i-1}+1)\time…

Power BI实用技巧——外部工具DAX studio

Power BI实用技巧——外部工具DAX studio 当你想要将Power BI表格对象数据导出,Power BI却告诉你:您的数据过大可能会执行一些数据抽样,点击继续导出一份CSV文件,却发现Power BI只能导出三万行数据,这该怎么办呢? 这里我们就要推荐一款非常实用的外挂级软件——DAX studi…

一款EF Core下高性能、轻量级针对分表分库读写分离的解决方案

前言 今天大姚给大家分享一款EF Core下高性能、轻量级针对分表分库读写分离的解决方案,开源(Apache License)的EF Core拓展程序包:ShardingCore。 ShardingCore项目介绍 ShardingCore是一款开源、简单易用、高性能、普适性,针对EF Core生态下的分表分库的扩展解决方案,支…

java中堆污染(heap pollution)以及@SafeVarargs注解使用

什么是堆污染 heap pollution堆污染发生在使用可变参数(varargs)或泛型时,将不兼容的类型插入到一个泛型对象中。这会导致在运行时尝试访问这些对象时发生 ClassCastException。例如:public static void heapPollutionExample(List<String>... stringLists) {Object[…

e语音 【删除文本右边字符】

删除 “#换行符”代码本文来自博客园,作者:__username,转载请注明原文链接:https://www.cnblogs.com/code3/p/18284992

从OpenAI停服看中国市场:国产替代崛起的机遇与挑战

一、OpenAI 停服事件背景 OpenAI 自 2020 年推出 GPT-3 以来,在全球范围内引起了极大的反响。其强大的自然语言处理能力使其成为许多企业和开发者的首选工具。然而,2024 年 6 月 25 日,许多中国用户收到了一封来自 OpenAI 的邮件,邮件中明确表示,自 2024 年 7 月 9 日起,…

云锵投资 2024 年 6 月简报

季报摘要行情:二次探底; 微盘策略:大幅回撤,逻辑基础小幅动摇,但继续运行; 本季度量化基金策略业绩:-4.3085%,中,全国排名:7532;平均 Beta:1.00; 本季度量化股票策略业绩:-16.8934%,差,全国排名:11198;平均 Beta:1.84;(优良中差,表明全国排名四位分) 行…

全网最适合入门的面向对象编程教程:09 类和对象的Python实现-类之间的关系,你知道多少?

本文主要对类之间的关系进行了基本介绍,包括继承、组合、依赖关系,并辅以现实中的例子加以讲解,同时说明了不同关系的特点和应用场景。全网最适合入门的面向对象编程教程:09 类和对象的 Python 实现-类之间的关系,你知道多少? 摘要: 本文主要对类之间的关系进行了基本介…

[LeetCode] 274. H-Index

意外的简单。 class Solution:def hIndex(self, citations: List[int]) -> int:sorted_list = sorted(citations, reverse=True)ret = 0for i,element in enumerate(sorted_list[:1000]):curr = min(i+1, element)if curr > ret:ret = currreturn ret

数据换机

图1为本系统的方法的流程示意图图2为首次拷贝到X中断需要遍历的文件示意图图3为非首次拷贝找到X中断点需要遍历的文件示意图 实现的功能支持换机对SD卡的数据迁移大文件按阈值切成切片文件小文件和切片文件按阈值分段拷贝切片文件的恢复小文件和切片文件从换机cache下恢复到三…

实战篇——文件上传漏洞upload-labs-master靶场实战一

实战篇——文件上传漏洞upload-labs-master靶场实战(1) 前端验证绕过 (1) 篡改js代码 直接上传一句话木马失败:查看页面源代码:可见前端通过checkFile函数对上传文件的后缀名进行了验证。 使用Tampermonkey自定义js脚本,用于删除form表单的onsubmit属性:启用脚本,刷新页面…

国产数据库人大金仓Kingbase数据迁移工具

转载:国产数据库人大金仓Kingbase数据迁移工具-CSDN博客 注意:Kingbase自带的迁移工具,只能从其它数据库迁移到Kingbase数据库 适配数据库安装的时候建议使用完全安装(数据库可以不启动),后续也可以全部默认(如安装数据库,相关 参数设置可参考人大金仓(Kingbase)部署…