Python 程序分析工具调研
Python 程序分析工具调研
Github 上的开源工具,*
号表示仓库已经不再维护
工具 | 描述 | 开发语言 |
---|---|---|
PySonar2 | 语义索引器,用于批量处理大型代码库。牺牲实时索引能力,使用过程间分析来推断变量、参数和函数的类型。目前作为大型代码索引服务的基础引擎,Sourcegraph 中也有使用该工具。 | Java |
Sourcegraph | 代码搜索和导航引擎,帮助阅读和理解大型项目的代码。目前支持 Go、Java、Python 等多种编程语言,能够以浏览器插件的形式提供在线代码阅读的功能。 | Go、TypeScript |
coala | 使用配置文件检测和修复代码,可自定义规则和标准检查代码质量,扩展性强。支持 Python、Java、C/C++、JavaScript 等多种编程语言,支持作为编辑器插件使用。 | Python |
vprof | 性能分析工具,为 Python 程序的运行时间、内存使用情况等提供交互式可视化,不适用于大型代码的分析。 | Python、JavaScript |
Code2Flow | 为动态语言生成生成调用图(Call Graph),目前支持 Python、JavaScript、Ruby、PHP。基础流程:AST -> 函数定义 -> 函数调用点 -> 连接点 ,主要是提供一个粗略的概览。缺点是没有定义的函数、不同命名空间相同名字的函数将被跳过等,因此并不适用于大型代码的分析。 |
Python、JavaScript |
pydeps | Python 模块依赖可视化,导出 .svg 或 .png 文件。只考虑导入的文件(模块必须安装),在 Python 字节码中查找导入操作码,同时支持外部模块的分析。 |
Python |
pycallgraph* | 为 Python 应用生成调用图(Call Graph),包括函数的调用次数、执行时间等信息,提供一定程度的性能分析功能。同时支持过滤函数,避免生成的图太大无法分析,默认导出 .png 文件。 |
Python |
undebt* | 执行大规模自动化代码重构,根据自定义模式对代码进行查找和替换,适用于任何语言。 | Python |
pyt* | 基于理论基础的 Python Web 应用静态分析(控制流图、定点、数据流分析),能够检测 SSRF、SQL 注入、XSS、目录遍历等攻击,支持自定义源点和汇点、传播污点的函数。目前已停更,作者建议使用 Pyre 。 | Python |
Pyre (Facebook) | 性能类型检查器,集成静态分析工具 Pysa(污点分析)Pysa 通过跟踪数据流实现安全检查,依赖类型注释,能够高速处理大型代码。 | OCaml、Python |
Bandit | 构建 AST 并使用插件检查安全问题,最初在 OpenStack 安全项目中开发,后来被重新定位到 PyCQA。主要用于扫描危险函数,支持自定义漏洞测试和扩展插件。 | Python |
Sourcetrail | 跨平台的源代码浏览器,支持 C/C++、Java、Python,提供搜索、代码、图形三个交互式视图。亮点是给出了源代码的结构,但只有符号名称。 | C++、Java |
radon | 计算源代码的度量(metrics),包括 McCabe、Halstead、可维护性索引三种度量指标,支持在 coala 中使用。主要用于评估代码的复杂度。 | Python |
xenon | 基于 radon 的监测工具,检查代码复杂性。可应用于 CI/CD,在每次提交代码时运行,根据自定义代码复杂性阈值返回成功或失败。 | Python |
jedi | Python 静态分析工具,侧重于自动补全和跳转,通常作为编辑器的插件使用。 | Python |
mypy | 静态类型检查器(PEP 484),能够对 Python 程序中的类型注释执行静态检查。 | Python |
pyright (Microsoft) | 可用于大型 Python 源代码库的快速类型检查器,使用内置的类型存根进行类型推断,可以在监视模式下运行,支持增量更新。 | TypeScript、Python |
pytype (Google) | 静态分析器,无需类型注释就能检查和推断 Python 代码的类型,也利用了类型存根(pyi 文件)。 | Python |
Vulture | 查找 Python 程序中未使用的代码(死代码),存在漏报,并且隐式调用可能会被误报。支持设置最小置信度、白名单等功能,可以对单个文件或目录的 py 文件执行分析。 | Python |
PyCG | 使用静态分析为 Python 代码生成调用图,支持高阶函数、类继承、导入的模块、嵌套定义。详见论文 ICSE 2021 paper | Python |
Wily | 复杂性检查 | Python |
McCabe | 复杂性检查 | Python |
it | 代码检查工具/框架 | Python |
以及一些闭源工具
工具 | |
---|---|
CodeQL | 代码分析引擎 |
Fortify SCA | 静态代码审计工具 |
Pylance (Microsoft) | 基于 pyright 的 Python 代码静态分析工具 |
DeepSource | 支持多种语言的静态分析,个人免费 |
Codacy | 能够通过静态代码分析获得关于安全问题、代码覆盖率、代码重复率、代码复杂性的信息 |
前段时间的 log4j 貌似就是用 CodeQL 找到的👍
Bandit
Bandit 可以用来搜索 Python 代码中常见的安全问题,在检测过程中,Bandit 会对每一份 Python 代码文件进行处理,基于 ast 模块生成抽象语法树,然后针对每一个 AST 节点运行相应的检测插件。完成安全扫描之后,Bandit 会直接给用户生成检测报告。
拿 keystone 源码进行测试,测试插件分组如下,可以通过配置进行选择:
ID | Description |
---|---|
B1xx | misc tests |
B2xx | application/framework misconfiguration |
B3xx | blacklists (calls) |
B4xx | blacklists (imports) |
B5xx | cryptography |
B6xx | injection |
B7xx | XSS |
测试 keystone
环境准备
1 | # virtualenv |
主要的功能就是黑名单和自定义检测规则。
1 | # 运行 Bandit |
导出的文件 test.html 显示扫描了 118379 行代码,蓝色表示低危,橙色表示中危,这里所有的都只出现在 tests 的测试文件中。
过滤测试文件夹,重新执行检测,得到 html 文件:testx.html 显示扫描 41415 行代码,没有用到危险函数。
Bandit 原先是 OpenStack 的项目,部分组件的开发有使用 Bandit 进行检查,其中就包括 keystone ,因此用 Bandit 扫描组件的意义可能不是很大。
1 | # 过滤测试文件夹 |
Vulture
同样利用了 ast 模块生成抽象语法树,在遍历时记录已定义和使用的对象名称,最后报告未使用的对象(死代码)。还通过查找 return、break、continue、raise、不满足条件的 if 条件、while 条件来检测不可达的代码。因为只考虑对象名称,没有考虑作用域,因此可能存在漏报,而且隐式调用可能会被误报。
测试 keystone
具体的安装与测试操作如下,执行结果导出为 unused.txt,最后给出了置信度。执行速度非常快,但给出的结果信息量少,只能作为简单的参考。
1 | # 创建文件夹 |
Pysa
入门教程可以看:Pyre 污点分析工具 Pysa 使用教程
测试 keystone
环境准备
安装依赖
1 | # 更新 Python3.8.x |
初始配置
1 | # 创建虚拟环境 |
分析 keystone 源码
下载 Victoria 版本的 keystone 源码并安装依赖,能够让 Pysa 使用和导入模块对应的污点模型,检测导入模块内部的污点源和汇。
1 | # 创建测试目录 |
初始化配置,添加类型注释(Python 3.5+)部分会失败,导入过滤器
1 | # 初始化配置 |
过滤器 pysa_filters 包含以下配置文件
- 5001-code-command-injection.json
- 5005-sql-injection.json
- 5011-userdata-to-filesystem.json
- 6065-argument-injection.json
- 6066-unsafe-deserialization.json
- 6073-server-side-template-injection.json
以 5001-code-command-injection.json 为例,设置不展示元数据(feature)以及显示的追踪长度
1 | { |
运行 Pyre 并将结果存储在 pysa-runs 文件夹,使用 SAPP 可视化展示
1 | # 运行 Pysa |
由于运行 OpenStack 服务的主机上 keystone 绑定了 5000 端口,而 SAPP 不提供修改端口的选项,所以重新弄了台主机专门用于分析。另外,SAPP 的 UI 默认绑定在 localhost 上,需要在本地使用 iptables 配置转发。
1 | # 启用本地转发 |
通过 Web UI 查看结果,一共找出 13 个问题,全是可能的 XSS 漏洞:
导入的过滤器可以在 Filter 中使用,不过 keystone 中没有检测出这些问题
点开一个问题的 Traces 展示:
UserControlled
类型的污点数据一直传播到 keystone.api.os_oauth1.RequestTokenResource.post 函数- 最短的传播距离
- 源点和汇点的追踪在 keystone.api.os_oauth1.RequestTokenResource.post 交汇
UserControlled
类型的污点数据从 keystone.api.os_oauth1.RequestTokenResource.post 开始,传播到 XSS 类型的汇点- 和交汇相同
使用 pyre query
导出数据:graph.json、hierarchy.json
1 | # 启动服务器 |
结语
差不多快半年前的东西了,而且目前也没有在做 Python 的静态程序分析。既然当时都调研和试用过了,那就稍微理一下存档这份流水账.jpg