借助 gosec 检查 Go 代码中的安全问题
发布时间:2022-07-11 16:05:14 所属栏目:安全 来源:互联网
导读:Go 语言 写的代码越来越常见,尤其是在容器、Kubernetes 或云生态相关的开发中。Docker 是最早采用 Golang 的项目之一,随后是 Kubernetes,之后大量的新项目在众多编程语言中选择了 Go。 像其他语言一样,Go 也有它的长处和短处(如安全缺陷)。这些缺陷可能
Go 语言 写的代码越来越常见,尤其是在容器、Kubernetes 或云生态相关的开发中。Docker 是最早采用 Golang 的项目之一,随后是 Kubernetes,之后大量的新项目在众多编程语言中选择了 Go。 像其他语言一样,Go 也有它的长处和短处(如安全缺陷)。这些缺陷可能会因为语言本身的缺陷加上程序员编码不当而产生,例如,C 代码中的内存安全问题。 无论它们出现的原因是什么,安全问题都应该在开发过程的早期修复,以免在封装好的软件中出现。幸运的是,静态分析工具可以帮你以更可重复的方式处理这些问题。静态分析工具通过解析用某种编程语言写的代码来找到问题。 开始使用 gosec 在开始学习和使用 gosec 之前,你需要准备一个 Go 语言写的项目。有这么多开源软件,我相信这不是问题。你可以在 GitHub 的 热门 Golang 仓库 中找一个。 本文中,我随机选了 Docker CE 项目,但你可以选择任意的 Go 项目。 安装 Go 和 gosec 如果你还没安装 Go,你可以先从仓库中拉取下来。如果你用的是 Fedora 或其他基于 RPM 的 Linux 发行版本: 复制 $ dnf install golang.x86_64 1. 如果你用的是其他操作系统,请参照 Golang 安装 页面。 使用 version 参数来验证 Go 是否安装成功: 复制 $ go version go version go1.14.6 linux/amd64 1. 2. 运行 go get 命令就可以轻松地安装 gosec: 复制 $ go get github.com/securego/gosec/cmd/gosec 1. 上面这行命令会从 GitHub 下载 gosec 的源码,编译并安装到指定位置。在仓库的 README 中你还可以看到 安装该工具的其他方法 。 gosec 的源码会被下载到 $GOPATH 的位置,编译出的二进制文件会被安装到你系统上设置的 bin 目录下。你可以运行下面的命令来查看 $GOPATH 和 $GOBIN 目录: 复制 $ go env | grep GOBIN GOBIN="/root/go/gobin" $ go env | grep GOPATH GOPATH="/root/go" 1. 2. 3. 4. 如果 go get 命令执行成功,那么 gosec 二进制应该就可以使用了: 复制 $ ls -l ~/go/bin/ total 9260 -rwxr-xr-x. 1 root root 9482175 Aug 20 04:17 gosec 1. 2. 3. 你可以把 $GOPATH 下的 bin 目录添加到 $PATH 中。这样你就可以像使用系统上的其他命令一样来使用 gosec 命令行工具(CLI)了。 复制 $ which gosec /root/go/bin/gosec $ 1. 2. 3. 使用 gosec 命令行工具的 -help 选项来看看运行是否符合预期: 复制 $ gosec -help gosec - Golang security checker gosec analyzes Go source code to look for common programming mistakes that 之后,创建一个目录,把源码下载到这个目录作为实例项目(本例中,我用的是 Docker CE): 复制 $ mkdir gosec-demo $ cd gosec-demo/ $ pwd /root/gosec-demo $ git clone https://github.com/docker/docker-ce.git Cloning into 'docker-ce'... remote: Enumerating objects: 1271, done. remote: Counting objects: 100% (1271/1271), done. remote: Compressing objects: 100% (722/722), done. remote: Total 431003 (delta 384), reused 981 (delta 318), pack-reused 429732 Receiving objects: 100% (431003/431003), 166.84 MiB | 28.94 MiB/s, done. Resolving deltas: 100% (221338/221338), done. Updating files: 100% (10861/10861), done. 代码统计工具(本例中用的是 cloc)显示这个项目大部分是用 Go 写的,恰好迎合了 gosec 的功能。 复制 $ ./cloc /root/gosec-demo/docker-ce/ 10771 text files. 8724 unique files. 2560 files ignored. ----------------------------------------------------------------------------------- Language files blank comment code ----------------------------------------------------------------------------------- Go 7222 190785 230478 1574580 YAML 37 4831 817 156762 Markdown 529 21422 0 67893 Protocol Buffers 149 5014 16562 10071 11. 使用默认选项运行 gosec 在 Docker CE 项目中使用默认选项运行 gosec,执行 gosec ./... 命令。屏幕上会有很多输出内容。在末尾你会看到一个简短的 “Summary”,列出了浏览的文件数、所有文件的总行数,以及源码中发现的问题数。 复制 $ pwd /root/gosec-demo/docker-ce $ time gosec ./... [gosec] 2020/08/20 04:44:15 Including rules: default 关于误判 在开始检查代码之前,我想先分享几条基本原则。默认情况下,静态检查工具会基于一系列的规则对测试代码进行分析,并报告出它们发现的所有问题。这是否意味着工具报出来的每一个问题都需要修复?非也。这个问题最好的解答者是设计和开发这个软件的人。他们最熟悉代码,更重要的是,他们了解软件会在什么环境下部署以及会被怎样使用。 这个知识点对于判定工具标记出来的某段代码到底是不是安全缺陷至关重要。随着工作时间和经验的积累,你会慢慢学会怎样让静态分析工具忽略非安全缺陷,使报告内容的可执行性更高。因此,要判定 gosec 报出来的某个问题是否需要修复,让一名有经验的开发者对源码做人工审计会是比较好的办法。 高优先级问题 从输出内容看,gosec 发现了 Docker CE 的一个高优先级问题,它使用的是低版本的 TLS( 传输层安全(Transport Layer Security)())。无论什么时候,使用软件和库的最新版本都是确保它更新及时、没有安全问题的最好的方法。 复制 [/root/gosec-demo/docker-ce/components/engine/daemon/logger/splunk/splunk.go:173] - G402 (CWE-295): TLS MinVersion too low. (Confidence: HIGH, Severity: HIGH) 172: > 173: tlsConfig := &tls.Config{} 174: 1. 2. 3. 4. 它还发现了一个弱随机数生成器。它是不是一个安全缺陷,取决于生成的随机数的使用方式。 复制 [/root/gosec-demo/docker-ce/components/engine/pkg/namesgenerator/names-generator.go:843] - G404 (CWE-338): Use of weak random number generator (math/rand instead of crypto/rand) (Confidence: MEDIUM, Severity: HIGH) 842: begin: > 843: name := fmt.Sprintf("%s_%s", left[rand.Intn(len(left))], right[rand.Intn(len(right))]) 844: if name == "boring_wozniak" /* Steve Wozniak is not boring */ { 1. 2. 3. 4. 中优先级问题 这个工具还发现了一些中优先级问题。它标记了一个通过与 tar 相关的解压炸弹这种方式实现的潜在的 DoS 威胁,这种方式可能会被恶意的攻击者利用。 复制 [/root/gosec-demo/docker-ce/components/engine/pkg/archive/copy.go:357] - G110 (CWE-409): Potential DoS vulnerability via decompression bomb (Confidence: MEDIUM, Severity: MEDIUM) 356: > 357: if _, err = io.Copy(rebasedTar, srcTar); err != nil { 358: w.CloseWithError(err) 1. 2. 3. 4. 它还发现了一个通过变量访问文件的问题。如果恶意使用者能访问这个变量,那么他们就可以改变变量的值去读其他文件。 复制 [/root/gosec-demo/docker-ce/components/cli/cli/context/tlsdata.go:80] - G304 (CWE-22): Potential file inclusion via variable (Confidence: HIGH, Severity: MEDIUM) 79: if caPath != "" { > 80: if ca, err = ioutil.ReadFile(caPath); err != nil { 81: return nil, err 1. 2. 3. 4. 文件和目录通常是操作系统安全的最基础的元素。这里,gosec 报出了一个可能需要你检查目录的权限是否安全的问题。 复制 [/root/gosec-demo/docker-ce/components/engine/contrib/apparmor/main.go:41] - G301 (CWE-276): Expect directory permissions to be 0750 or less (Confidence: HIGH, Severity: MEDIUM) 40: // make sure /etc/apparmor.d exists > 41: if err := os.MkdirAll(path.Dir(apparmorProfilePath), 0755); err != nil { 42: log.Fatal(err) 1. 2. 3. 4. 你经常需要在源码中启动命令行工具。Go 使用内建的 exec 库来实现。仔细地分析用来调用这些工具的变量,就能发现安全缺陷。 复制 [/root/gosec-demo/docker-ce/components/engine/testutil/fakestorage/fixtures.go:59] - G204 (CWE-78): Subprocess launched with variable (Confidence: HIGH, Severity: MEDIUM) 58: > 59: cmd := exec.Command(goCmd, "build", "-o", filepath.Join(tmp, "httpserver"), "github.com/docker/docker/contrib/httpserver") 60: cmd.Env = append(os.Environ(), []string{ 1. 2. 3. 4. 低优先级问题 在这个输出中,gosec 报出了一个 unsafe 调用相关的低优先级问题,这个调用会绕开 Go 提供的内存保护。再仔细分析下你调用 unsafe 的方式,看看是否有被别人利用的可能性。 复制 [/root/gosec-demo/docker-ce/components/cli/cli/command/image/build/context.go:172] - G104 (CWE-703): Errors unhandled. (Confidence: HIGH, Severity: LOW) 171: err := tar.Close() > 172: os.RemoveAll(dockerfileDir) 173: return err 1. 2. 3. 4. 自定义 gosec 扫描 使用 gosec 的默认选项会带来很多的问题。然而,经过人工审计,随着时间推移你会掌握哪些问题是不需要标记的。你可以自己指定排除和包含哪些测试。 (编辑:应用网_丽江站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |