本文将探讨在基于WASM的牧云插件系统开发中探针开发语言的选择。我们将对比不同语言在性能、安全性、易用性等方面的优缺点,并解释我们为什么以及最终选择了哪种语言作为探针开发语言。
这是系列文章“主机Agent插件引擎开发故事”的第四篇,后续将会持续更新。该系列文章将带领您深入探究长亭牧云团队主机Agent插件引擎的开发历程,内容涵盖技术选型、插件接口设计、组件通信框架等多个方面,并详细讲解背后的原理和实现方式,无论您是网络安全专业人员还是对技术开发感兴趣的读者,都可以从中得到收获。我们希望通过分享在开发过程中面临的挑战、解决方案以及实践经验,提供深入见解和有价值的技术参考,帮助读者了解如何构建高效可靠的安全产品,共同推动安全技术社区的发展。
在主机安全系统的架构中,Agent 程序非常重要。其不但是实施基本功能的重要模块,而且是一个主机安全系统中具体安全能力的承载者。其运行不但要覆盖入侵检测、资产清点、应用监控、漏洞检测、帮助优化性能和快速排查问题等,还必须达到高度的稳定性、可靠性和安全性。因此,认真选择探针使用哪种语言开发是一个非常非常重要的问题。
根据主机安全系统的实际需求,对探针开发语言的选择至少要满足以下基本原则:

使用 C++ 编写 Agent 程序是在主机安全领域中非常常见的一种做法。使用 C 编写相对不那么常见,但非常适合满足特定场景的特殊需求。针对主机安全场景分析如下:
C++ 必然就要谈到性能,几乎可以说是蓝星上除了汇编以外最快的东西了,能生成最精简的机器码,提供理论上几乎最高的性能,因此从这个角度来看非常适合编写主机 Agent。C++,熟悉网络安全的人一定知道,这是内存安全问题的重灾区,几乎不能更重了。从这个角度来看,又非常不适合编写主机 Agent 使用。QT),那么跨平台是非常完美的。可惜我们没有能直接用的框架。C++ 工程中极为棘手的一个问题。C 或者 C++。但是其他方面就不好说了。
使用 Java 编写 Agent 程序在主机安全领域也是一种常见的做法,针对主机安全场景分析如下:
C++ 相提并论,但也非常不错。但其存在内存占用较大的问题,是我们不太喜欢的。Java 是一个内存安全的带垃圾回收的语言,少用一些花哨的东西加上良好设计的话,安全性也不需要过于担心。JVM 帮我们提供了平台兼容性,但 JVM 如果不支持,那就是真的不支持。通常这不是个问题,但有问题的时候解决问题的难度比较大。C++ 要统一些。
使用 Python 编写 Agent 程序相对不那么常见,但同样存在。针对主机安全场景分析如下:
C++ 或者 Rust 编写底层模块,另外新版本越来越快了。同时还有一些号称比官方 CPython 更快的版本。Python 2。
使用 Ruby 编写 Agent 并不是一种常见的做法,但有知名厂商珠玉在前,我们针对主机安全场景来分析一下:
Python 类似。Ruby 写的(比如 Metasploit),所以在安全社区是有些影响力的。
使用 Go 编写 Agent 是一种我们的做法,针对主机安全场景分析如下:
C++ 的情况下是很好的选择。唯一的问题是 GC 提供的控制性比较弱,相关的问题不太好解决。CGO 和许多生态都能接轨(虽然 CGO 真的很难用)。go mod 了,所以还行。
使用 Rust 编写 Agent 是一种新兴的做法,针对主机安全场景分析如下:
C++ 同级别的性能,有时候更好。独特的内存管理方式使得内存占用可控。GC 的情况下作为一个编译型无虚拟机语言保证了内存安全,非常强。C 和 C++。Rust 重写的东西终究会被 Rust 重写。常见的都有了,即将啥都有。天然能和 C 世界接轨,而且没有 CGO 的缺陷(比如不可避免的内存拷贝)。其他还有主要使用 Perl、Bash 等实现的等等,都显然不太能用,理由不多说了。
比较各种常见的选择,可以发现,如果同时想要速度快、内存占用小、没有太多安全担忧、社区支持强、能适应各种复杂场景,基本上主要就是从 Go 和 Rust 里面选。Go 成熟相对更早一些,所以早期牧云的探针语言选型就是 Go。
随着数年的深度使用,以及 Go 越来越向云原生方向走,对社区有强烈呼声的增强内存控制能力、提供好用的动态加载机制等的持续忽视,以及积极抛弃旧操作系统支持的政策,对主机安全系统的拓展性和兼容性都带来了许多困难。在之前的文章中提到过,为了满足牧云自身的兼容性需求、性能要求和可拓展需求,我们做了许多努力,提出了不少技术创新方案。截至目前,因为修修补补,我们的 Go 版本停止在了 Go 1.17.2-patch。后缀的这个 patch 代表我们做的各种定制。

等到最近的版本终于加上了堆内存限制、手动管理内存等特性,诞生了WAZERO这样的纯 Go 写的 WASM 引擎解决拓展性问题的时候,我们已经积重难返了。
解决积重难返最好的办法是什么,当然是推倒重写(开玩笑的)。
但是如果要再次升级 Go 版本就意味着所有兼容性适配和微调都要重做,而且即使升级到最新版本也并不能解决所有问题(比如低版本系统兼容适配等)。这个时候我们看到 Rust 语言逐渐兴起,是一个非常好的选择。在 Rust 之前,我们唯一的选择就是 C++;但是现在有了 Rust,我们就不必为了获得足够的灵活性承受 C++ 的维护之痛了。

Rust官网首页有一句话是这么说的:Hundreds of companies around the world are using Rust in production today for fast, low-resource, cross-platform solutions.
不得不承认,“fast, low-resource, cross-platform solutions”的说法真的抓住了我们这群做主机安全产品的开发者的心。
上一篇:【牧云插件系统选型斗争】
系列文章目录:【预告】主机Agent插件引擎开发故事汇总