Git提交钩子触发OSV-Scanner漏洞扫描

作者:Sender  来源:wavecn.com  发布日期:2023-08-15  最后修改日期:2023-08-15

继续关于 Google 的开源漏洞扫描器 OSV-Scanner。在上一篇《开源漏洞扫描器 OSV-Scanner 的新进展》的最后提到 OSV-Scanner 的一些自动化执行部署方式,比如定时自动检查和通过 Git 的钩子实现提交时检查等。

article banner

笔者:国际认证信息系统审计师、软考系统分析师

那么如何实现代码提交到 Git 仓库时联动触发 OSV-Scanner,先对项目进行漏洞扫描,扫描通过了才提交?

这就需要设置 GIT 的钩子。

本篇内容只是作为一种使用方法的示例教学,并非最有效的解决方案。读者需要对 GIT 的使用有一定的熟悉程度,以及知道如何编写 BASH 脚本等。

另外,在测试过程中发现,TortoiseGit 这个与 Windows 桌面文件管理整合在一起的 GIT 外壳工具的钩子功能在当前版本 2.14.0.1 可能有 BUG,无论钩子执行后返回值是0还是1,提交都会继续执行。因此本文只通过 GIT-BASH 命令行进行。

一、首先要搞清楚什么是GIT钩子

简单说,钩子是 GIT 在执行过程中的关键点上的触发动作,通过钩子可以自动运行指定的应用程序。相关文档位于:

https://git-scm.com/docs/githooks

由于单个应用程序可以实现的功能和逻辑一般都是单一的,所以基本上都是编写脚本,通过钩子触发运行脚本,由脚本的内在逻辑执行应用程序实现需要的处理操作,基于应用程序输出重定向的方法处理应用程序的输出,最后对于属于预操作类别的钩子,通过返回0或非0值以控制 GIT 的操作是否继续执行。

需要注意的是 GIT 提供了28种钩子类型,本篇需要使用到的是Pre-commit钩子。该钩子在用户点击提交对话框的OK按钮时触发,触发动作完成后才会执行实际的提交动作。

Pre-commit 钩子支持根据触发运行的程序的返回值决定是否继续执行。若触发的动作返回值为0,则继续执行提交,如果返回非0值则中止执行提交。

二、如何写GIT钩子脚本

很显然我们需要一些编写脚本的参考。安装 GIT 后,在如下位置可以找到钩子的参考模版:

C:\Program Files\Git\mingw64\share\git-core\templates\hooks

其中的 pre-commit.sample 是本次要参考的。这些模版也会在创建代码仓库后自动复制到仓库的 .git\hooks 目录中。

注意这些示例是 Bash 脚本,而不是 Windows 的传统 command 脚本或现代的 PowerShell 脚本。

GIT 的安装自带了 mingw64,常用的 Linux 命令行工具都具备,位于

C:\Program Files\Git\usr\bin

所以我们写脚本基于 Bash 去写,方便以后跨平台。

脚本的内在逻辑也不复杂:调用 OSV-Scanner 扫描代码仓库目录,扫描结果输出重定向到临时文件。当 OSV-Scanner 完成扫描后,判断其返回值如果非0(即有问题)则向使用人显示被重定向保存到临时文件的扫描输出内容并返回非0值,否则就直接返回0。

用 LibreOffice Draw 画的流程图大致如下,为充分说明而与实际代码相比稍有啰嗦:

precommit_osv_scanner_workflow.webp

代码如下:

#!/bin/sh

# 删除之前的检查输出,这里应进一步改写为在系统临时文件夹内创建临时文件。
rm -f osv_scan_result.txt

/c/users/用户名/appdata/local/programs/osv-scanner/osv-scanner.exe -r --skip-git ./ > osv_scan_result.txt 2>&1

if [ "$?" != "0" ]     
then
  cat osv_scan_result.txt >&2
  echo OSV-Scanner扫描结果显示存在漏洞,请检查修正后重新提交! >&2
  exit 1
else
  exit 0
fi
三、GIT的安装注意

顺带提一下 GIT 在 WINDOWS 环境下安装时要注意的选项:

1、选择 GIT-BASH 环境使用 GIT

如果是在 Windows 环境下同时使用多种 IDE 工具链的高产程序员,GIT 的配置很容易相互打架。此时可以选择最小影响的这个选项,仅在 GIT-BASH 环境使用 GIT。

2-use-git-from-git-bash-only.webp

2、保留源文件换行符

无论工作环境情况如何,都应该保留源文件换行符不变,留给编辑器去自动处理。除非确实没有能透明处理不同换行符的编辑器,但现在都什么年代了。

3-checkout-as-is-commit-as-is.webp

四、配置OSV-Scanner

OSV-Scanner 本身不需要配置,要处理的是把 OSV-Scanner 放哪里的问题。

由于这是 Windows 环境,按最良好的规范是面向个人账号做配置,那么应该放到个人账号下的应用程序空间下的子目录内:

C:\Users\用户名\AppData\Local\Programs\osv-scanner

同时为了方便后续升级,把 OSV-Scanner 的执行文件改名,简化为 osv-scanner.exe。

以上配置已经在前面的脚本文件中有体现了。

如果打算面向计算机(多账号共用)而不是面向账户做配置,可以在C:\Users\Public下建文件夹来放置。

五、测试代码提交

为确认检查的有效性,要准备已经确认存在缺陷漏洞的开源组件。我们可以通过 CVE 清单去选择,比如 CVE-2022-24785,属于 Moment.js 的7.5分漏洞:

https://nvd.nist.gov/vuln/detail/CVE-2022-24785

将该版本代码引入到自己的测试项目中,然后测试提交前的扫描,过程如下:

(1)启动 git-bash,创建自己的GIT项目

(2)引入 Moment.js 作为项目组件,用 RESET 操作回退到缺陷修补前的版本。

(3)设置钩子,选择最常规的做法,把写好的钩子脚本放到GIT项目文件夹的 .git\hooks 目录内,直接命名为 pre-commit:

hook-scripts.webp

(4)测试提交,随便编写一个文件,比如 readme.md,然后 COMMIT 提交。

(5)观察拦截情况,osv-scanner 会发现代码仓库内存在缺陷版本,阻止提交。

USER@MYDESKTOP MINGW64 ~
$ cd /e/

USER@MYDESKTOP MINGW64 /e
$ git init MyProject
Initialized empty Git repository in E:/MyProject/.git/

USER@MYDESKTOP MINGW64 /e
$ cd MyProject/.git/hooks/

USER@MYDESKTOP MINGW64 /e/MyProject/.git/hooks (GIT_DIR!)
$ cp /c/users/USER/appdata/local/programs/osv-scanner/pre-commit .

USER@MYDESKTOP MINGW64 /e/MyProject/.git/hooks (GIT_DIR!)
$ cd /e/MyProject

USER@MYDESKTOP MINGW64 /e/MyProject (master)
$ git submodule add https://github.com/moment/moment/
Cloning into 'E:/MyProject/moment'...
remote: Enumerating objects: 28614, done.
remote: Total 28614 (delta 0), reused 0 (delta 0), pack-reused 28614
Receiving objects: 100% (28614/28614), 20.65 MiB | 1.56 MiB/s, done.
Resolving deltas: 100% (19884/19884), done.

USER@MYDESKTOP MINGW64 /e/MyProject (master)
$ cd moment

USER@MYDESKTOP MINGW64 /e/MyProject/moment (develop)
$ git reset --hard f2a813afcfd0dd6e63812ea74c46ecc627f6a6a6
HEAD is now at f2a813af [misc] Fix indentation (according to prettier)

USER@MYDESKTOP MINGW64 /e/MyProject/moment (develop)
$ cd ..

USER@MYDESKTOP MINGW64 /e/MyProject (master)
$ touch readme.md

USER@MYDESKTOP MINGW64 /e/MyProject (master)
$ git add readme.md

USER@MYDESKTOP MINGW64 /e/MyProject (master)
$ git commit
Scanning dir ./
scan failed for git repository, E:\MyProject\.git: reference not found
Scanned E:\MyProject\moment\package-lock.json file and found 615 packages
+-------------------------------------+-----------+----------------------+---------+--------------------------+
| OSV URL (ID IN BOLD)                | ECOSYSTEM | PACKAGE              | VERSION | SOURCE
|
+-------------------------------------+-----------+----------------------+---------+--------------------------+
| https://osv.dev/GHSA-v88g-cgmw-v5xw | npm       | ajv                  | 6.12.2  | moment\package-lock.json |
| https://osv.dev/GHSA-93q8-gq69-wqmw | npm       | ansi-regex           | 4.1.0   | moment\package-lock.json |
| https://osv.dev/GHSA-93q8-gq69-wqmw | npm       | ansi-regex           | 5.0.0   | moment\package-lock.json |
| https://osv.dev/GHSA-fwr7-v2mv-hh25 | npm       | async                | 2.6.3   | moment\package-lock.json |
| https://osv.dev/GHSA-w573-4hg7-7wgq | npm       | decode-uri-component | 0.2.0   | moment\package-lock.json |
| https://osv.dev/GHSA-273r-mgr4-v34f | npm       | engine.io            | 4.1.1   | moment\package-lock.json |
| https://osv.dev/GHSA-r7qp-cfhv-p84w | npm       | engine.io            | 4.1.1   | moment\package-lock.json |
| https://osv.dev/GHSA-74fj-2j2h-c42q | npm       | follow-redirects     | 1.13.2  | moment\package-lock.json |
| https://osv.dev/GHSA-pw2r-vq6v-hr8c | npm       | follow-redirects     | 1.13.2  | moment\package-lock.json |
| https://osv.dev/GHSA-957j-59c2-j692 | npm       | getobject            | 0.1.0   | moment\package-lock.json |
| https://osv.dev/GHSA-ww39-953v-wcq6 | npm       | glob-parent          | 5.1.1   | moment\package-lock.json |
| https://osv.dev/GHSA-j383-35pm-c5h4 | npm       | grunt                | 1.3.0   | moment\package-lock.json |
| https://osv.dev/GHSA-rm36-94g8-835r | npm       | grunt                | 1.3.0   | moment\package-lock.json |
| https://osv.dev/GHSA-765h-qjxv-5f44 | npm       | handlebars           | 4.7.6   | moment\package-lock.json |
| https://osv.dev/GHSA-f2jv-r9rf-7988 | npm       | handlebars           | 4.7.6   | moment\package-lock.json |
| https://osv.dev/GHSA-896r-f27r-55mw | npm       | json-schema          | 0.2.3   | moment\package-lock.json |
| https://osv.dev/GHSA-9c47-m6qq-7p4h | npm       | json5                | 2.1.3   | moment\package-lock.json |
| https://osv.dev/GHSA-jg8v-48h5-wgxg | npm       | jszip                | 3.5.0   | moment\package-lock.json |
| https://osv.dev/GHSA-36fh-84j7-cv5h | npm       | jszip                | 3.5.0   | moment\package-lock.json |
| https://osv.dev/GHSA-7x7c-qm48-pq9c | npm       | karma                | 6.1.1   | moment\package-lock.json |
| https://osv.dev/GHSA-rc3x-jf5g-xvc5 | npm       | karma                | 6.1.1   | moment\package-lock.json |
| https://osv.dev/GHSA-29mw-wpgm-hmr9 | npm       | lodash               | 4.17.20 | moment\package-lock.json |
| https://osv.dev/GHSA-35jh-r3h4-6jhm | npm       | lodash               | 4.17.20 | moment\package-lock.json |
| https://osv.dev/GHSA-82v2-mx6x-wq7q | npm       | log4js               | 6.3.0   | moment\package-lock.json |
| https://osv.dev/GHSA-f8q6-p94x-37v3 | npm       | minimatch            | 3.0.4   | moment\package-lock.json |
| https://osv.dev/GHSA-xvch-5gv4-984h | npm       | minimist             | 1.2.5   | moment\package-lock.json |
| https://osv.dev/GHSA-hj48-42vr-x3v9 | npm       | path-parse           | 1.0.6   | moment\package-lock.json |
| https://osv.dev/GHSA-hrpp-h998-j3pp | npm       | qs                   | 6.5.2   | moment\package-lock.json |
| https://osv.dev/GHSA-hrpp-h998-j3pp | npm       | qs                   | 6.7.0   | moment\package-lock.json |
| https://osv.dev/GHSA-p8p7-x288-28g6 | npm       | request              | 2.88.2  | moment\package-lock.json |
| https://osv.dev/GHSA-c2qf-rxjj-qqgw | npm       | semver               | 5.7.1   | moment\package-lock.json |
| https://osv.dev/GHSA-c2qf-rxjj-qqgw | npm       | semver               | 6.3.0   | moment\package-lock.json |
| https://osv.dev/GHSA-qm95-pgcg-qqfq | npm       | socket.io-parser     | 4.0.4   | moment\package-lock.json |
| https://osv.dev/GHSA-cqmj-92xf-r6r9 | npm       | socket.io-parser     | 4.0.4   | moment\package-lock.json |
| https://osv.dev/GHSA-72xf-g2v4-qvf3 | npm       | tough-cookie         | 2.5.0   | moment\package-lock.json |
| https://osv.dev/GHSA-fhg7-m89q-25r3 | npm       | ua-parser-js         | 0.7.24  | moment\package-lock.json |
| https://osv.dev/GHSA-cf4h-3jhx-xvhq | npm       | underscore           | 1.11.0  | moment\package-lock.json |
| https://osv.dev/GHSA-j8xg-fqg3-53r7 | npm       | word-wrap            | 1.2.3   | moment\package-lock.json |
| https://osv.dev/GHSA-6fc8-4gx4-v693 | npm       | ws                   | 7.4.3   | moment\package-lock.json |
| https://osv.dev/GHSA-c4w7-xm78-47vh | npm       | y18n                 | 4.0.0   | moment\package-lock.json |
+-------------------------------------+-----------+----------------------+---------+--------------------------+
OSV-Scanner扫描结果显示存在漏洞,请检查修正后重新提交!
六、效果评价

最后还是要先强调,本文只是示例。如果要用在生产中,最起码脚本程序还要做很多修改才能达到保证生产力的同时实现安全限制的平衡。

其次是 osv-scanner(测试版本1.3.4) 离理想状态还差好远。关键在于它的扫描行为是基于 package source 或者 git commit 产生的 hash 值等元信息去匹配 CVE 记录。如果这些元信息被改动,扫描就不会给出结果。从实际出发,需要能扫描到源代码本身的扫描工具。

再次是在测试期间发现版本1.3.6不稳定,扫描时会崩溃报错:

panic: runtime error: index out of range [0] with length 0

题图来自Pixabay公共图片库

本栏目相关
  •  2024-02-22 开源杀毒软件 ClamAV 1.3.0 新版释出,支持解析检查 Microsoft OneNote 附件
  •  2022-05-11 CIS-CAT 配置评估工具介绍及操作实践
  •  2022-03-16 Windows 系统安全基线及软件工具介绍
  •  2022-08-28 网络攻防中的色彩象征
  •  2022-03-11 安装RHEL/CentOS时如何选择配置安全策略?
  •  2022-03-17 详细了解微软安全合规工具包(SCT)
  •  2022-03-25 从甲方角度介绍“CIS互联网安全中心”
  •  2023-01-06 MSSQL数据库自动备份和自动复制转移备份
  •  2022-03-28 如何应用CIS互联网安全中心发布的《CIS关键安全控制措施集》之一:总览
  • 微信订阅号二维码

    本页网址二维码: