FIPS 140 认证与 Golang
FIPS 140 ( Federal Information Processing Standard Publication 140 )
FIPS 140 是美国 NIST 制定的密码模块安全认证标准。此标准评估特定密码模块或库是否满足 NIST 定义的安全要求。因此,通过 FIPS 140 认证意味着该模块正式具备可信赖的安全性,并可用于金融、医疗、国防等对安全性要求较高的领域。
FIPS 140 自 1994 年首次制定以来,于 2001 年修订为 FIPS 140-2,并于 2019 年修订为 FIPS 140-3。目前,许多系统和应用程序仍然要求 FIPS 140-2 或 FIPS 140-3 认证。
FIPS 140 与编程语言
基于此原因,获得 FIPS 140 认证的密码模块已成为多种编程语言和环境中的事实标准。其中代表性的有 OpenSSL, BoringSSL, LibreSSL, NSS 等,这些模块在对安全性要求较高的应用程序中得到了最广泛的应用。
大多数 FIPS 140 认证模块均采用 C 或 C++ 编写。因此,PHP, Python, Javascript 等语言通常不直接使用这些模块,而是通过外部 Provider 模块进行集成,以构建 FIPS 环境。然而,这种方法存在一些局限性。
版本不匹配问题
FIPS 140 认证仅针对特定版本授予。因此,若要使用最新版本的模块,则需重新经历认证过程,在此过程中可能出现应用程序所用模块与 FIPS 认证模块之间的版本不匹配。若使用未经授权的版本,则该环境将不再被视为 FIPS 认证环境。
动态加载与性能下降
大多数语言以动态库的形式加载并使用 FIPS 140 认证模块。此方式可能导致初始化和执行过程中的性能下降,并且在运行时出现问题时,存在直接影响整个应用程序稳定性的风险。
安全漏洞
如前所述,在像 OpenSSL Provider 这样集成外部模块的架构中,存在该模块的安全漏洞直接传播到应用程序的风险。此外,应用程序与外部模块之间的通信层本身也成为额外的攻击面,需要额外的安全层来保护。这会增加复杂性,从而可能产生意想不到的漏洞。
FIPS 140 与 Golang
鉴于此,Golang 采取了不同的策略。Go 不依赖外部工具进行 FIPS 140 认证,而是选择在官方加密库中直接提供支持。因此,开发人员无需安装或配置额外的 Provider,只需使用标准 crypto 包并激活 FIPS 认证模式 (GOFIPS=1) 即可。在此过程中,消除了与外部模块的通信边界,从而增强了安全性,并且只需分发静态编译的单一二进制文件,从而简化了操作。
FIPS 140-2 与 Golang
为此,Golang 将从 BoringSSL 派生的 BoringCrypto 模块内嵌到 Go 运行时中,从而获得了 FIPS 140-2 认证。BoringCrypto 在 Go 1.19 版本之后的特定发行版中可激活,通过它,Go 应用程序无需任何外部模块即可构建 FIPS 140-2 认证环境。
然而,由于 BoringCrypto 基于 OpenSSL,因此仍存在对 C 语言的依赖。这意味着 Go 应用程序无法完全独立地构建为二进制文件,并且存在需要同时分发所需 C 库的限制。
FIPS 140-3 与 Golang
Go 团队为克服这些局限性,已对现有 Go 标准 crypto 库进行了改进,以符合 FIPS 140-3 规范。此改进模块自 Go 1.21 版本起开始实验性提供,目前正在接受 NIST 的 FIPS 140-3 认证审查。NIST FIPS 140-3 审查中的模块列表
这表明 Go 加密库的成熟度,通过此改进,Go 能够以完全独立的单一二进制形式提供 FIPS 140-3 认证环境。
此外,Go 团队不仅满足了 FIPS 140-3 标准,还自主强化了安全性。
Fail Fast
Go 的 FIPS 模式采用 Fail Fast 安全模型,当调用未经认证的算法时,会通过 panic 立即中断执行。这与其它语言基于 Provider 的模型可能留下 fallback 可能性不同,它在安全性和合规性方面提供了更严格和明确的保证。
Hedged Signature
FIPS 140-3 标准推荐在 ECDSA 签名时采用 RFC6979 方式。然而,Go 在此基础上引入了 Hedged 方式,从而更强有力地应对签名过程中可能发生的侧信道攻击。
增强型随机数生成器
Go 的随机数生成器在用户空间使用 DRBG (Deterministic Random Bit Generator) 的同时,还额外注入对操作系统内核的熵,从而不仅在用户空间,而且在内核空间也生成高质量的随机数。这进一步增强了随机数生成器的安全性。