Go项目的交叉编译
如果你是一名Go开发者,那么你一定知道交叉编译是这门语言的一个重要特性。它可以让你在一个平台上编译代码,然后在另一个平台上使用。比如,你可以在Mac上编译代码,然后在Windows机器上使用。这对于想要在多个平台上使用同一份代码的开发者来说非常棒。
然而,当你在为Windows编译Go项目时,会遇到一个大问题。
问题
当Go项目编译为Windows可执行文件时,会生成一个单一的二进制文件(在Windows上是.exe文件)。Go编译这个二进制文件的过程相对独特,经常会让杀毒软件产生困惑,导致将二进制文件错误地检测为病毒。
这当然是非常麻烦的,因为可能会导致浏览器根本不允许下载编译后的文件。这在我的一个开源项目中就出现过。用户无法下载新版本。如果他们在Chrome中禁用了病毒扫描器并下载了可执行文件,那么在下载后,Windows Defender会直接删除文件。这使得在不关闭整台计算机的病毒保护的情况下安装该程序变得不可能。
问题分析
我写了一个简单的Go程序“Hello World”,并将其编译为Windows、Linux和macOS平台。下面是不同病毒扫描器的测试结果:
测试的源代码
由于macOS的测试结果与Linux相同,所以我没有包含macOS的测试结果。
所有程序都是使用最新版本(v1.19.2)编译的。
编译为Windows
64位:GOOS=windows GOARCH=amd64
32位:GOOS=windows GOARCH=386 go build .
编译为Linux
64位:GOOS=linux GOARCH=amd64 go build .
32位:GOOS=linux GOARCH=386 go build .
尽管这些构建都是一个简单的“Hello World”程序,但Windows构建会触发一些病毒扫描器。在我们的“Hello World”示例中,Windows Defender没有检测到任何问题。不幸的是,这在真实程序中经常发生。
此外,可以看到32位构建比64位构建更容易被检测到。
这里令人担忧的是,几乎所有的Windows构建都会被检测为病毒,无论程序实际执行什么操作。特别是在开源场景中,这是一个巨大的打击。通常情况下,这些项目背后没有大公司,而是由私人维护。在许多情况下,错误的病毒检测会导致无法在Windows下安装项目,除非手动覆盖病毒保护,这通常被认为是不好的。
沟通不畅
在我看来,主要问题在于Google和Microsoft之间缺乏沟通。
Google拥有Go,因此Google应该努力确保用Go编写的程序在每个支持的平台上都能平稳运行。毕竟,Go的最大特点之一就是交叉编译。另一方面,Microsoft也应该确保其病毒扫描器不会仅仅因为某个程序使用某种编程语言就怀疑它是有害程序。特别是由于微软也拥有GitHub,微软应该对帮助开源社区有特别的兴趣。
因此,最好的解决方案是让Google和微软的相关团队聚在一起,试图解决这个问题。
毕竟,这个问题已经存在了很多年,而Google唯一正式发布的是一个FAQ条目,其中将这种行为归类为正常。这不应该是正常的。
商业病毒扫描程序经常会被Go二进制文件的结构所困惑,因为他们不像编译自其他语言的那些程序那样常见。(来源:https://go.dev/doc/faq#virus)
解决方法
不幸的是,这个问题不容易解决。但是,有一些方法可以帮助防止可执行文件被视为病毒。
导入"C"
在互联网上,你经常会读到,导入"C"应该有所帮助。由于使用了CGO进行构建,二进制文件的结构会发生一些变化,应该不太容易出现误报。
看,这是真的。现在,我们只有在64位版本中发现了dive,而不是之前的七个误报。
不幸的是,这还不足以保证一个良好的部署。
使用CGO的AMD64构建https://www.virustotal.com/gui/file/74ccb397cb590e3326602400521b640a60be78c9b54759550aff810940942507?nocache=1
代码签名
另一种方法称为"代码签名"。代码签名是将二进制文件进行加密签名以验证程序的来源和开发人员的过程。但是,要签名一个二进制文件,你需要一个"代码签名证书"。这些证书的价格每年从几百欧元开始。更好的证书,Windows直接信任并且不再触发smartscreen消息,每年的价格可以高达数千欧元。
这是最常建议的解决方案。不幸的是,签名的二进制文件并不能证明没有病毒。证书只证明了谁构建了程序。因此,即使在这里,也可能出现虚假的病毒信息。
混淆构建
另一种(常常被建议的)方法是混淆构建。这样,二进制文件的结构就会发生变化,不再存储诸如变量名之类的东西(它们会被替换为随机值)。我试过了,这是一个64位构建的结果:
正如你所看到的,误报甚至翻了一番。这并不令人惊讶,因为混淆构建比非混淆构建更不透明。病毒经常被混淆以隐藏它们的意图。
例如,使用UPX压缩二进制文件,结果是相同的原因。
手动从病毒数据库中删除二进制文件
这是最安全的方法。许多病毒扫描程序,包括Microsoft Defender,在报告虚假检测时允许。Microsoft Defender需要在网上填写一个表格。
不幸的是,这种方法不能完全自动化部署流程。每个版本都必须手动提交给Microsoft(和其他病毒扫描器公司)进行验证。
其他方法
有一些方法可以避免病毒检测,但它们不太用户友好。
- 告诉你的用户使用"go install your.package/path@latest"Go install会在用户的设备上编译程序。这不会触发病毒检测。
- 使用docker镜像通过编译docker镜像,你的用户可以在一个隔离的环境中运行该镜像。这通常对于测试CLI很好,但在实际情况下,你的用户可能希望在主机机器上运行CLI。
结论
现在,等待可能是你能做的最好的事情。随着每天编译更多的Go项目,病毒扫描程序应该会更可靠地学习其结构并检测到它。也许Google和Microsoft甚至会联合起来,更快地解决这个问题。只有时间才能告诉我们。
译自:https://betterprogramming.pub/a-big-problem-in-go-that-no-one-talks-about-328cc3e71378
评论(0)