Golang CBOR库推荐 - 轻量、高效、稳定,恶意数据零崩溃,支持encoding/json API及toarray/keyasint结构体标签 (fxamacker/cbor v1.3)
Golang CBOR库推荐 - 轻量、高效、稳定,恶意数据零崩溃,支持encoding/json API及toarray/keyasint结构体标签 (fxamacker/cbor v1.3)
这个库是做什么的? fxamacker/cbor 对 CBOR 进行编码和解码,就像 encoding/json 对 JSON 所做的那样。
什么是 CBOR? CBOR (RFC 7049) 是一种受 JSON 和 MessagePack 启发的二进制数据格式。CBOR 被用于 IETF 互联网标准中,例如 COSE (RFC 8152) 和 CWT (RFC 8392 CBOR Web Token)。WebAuthn 也使用 CBOR。
既然已有其他库,为何还要创建这个? 我需要在 Go 中使用 CBOR,但希望库体量小,并且不必担心微小的恶意 CBOR 消息可能导致整个系统崩溃。
:point_right: 我发现一个 GitHub 项目用这个库替换了一个拥有 1000+ 星标的库,因为外部安全审计发现,微小的恶意 CBOR 消息能够耗尽另一个库的系统资源。
为什么项目应该选择这个 CBOR 库? 它不会崩溃,并且具备均衡的特性:小巧、快速、可靠且易用。
- :atom_symbol: 小巧且自包含。它编译后小于 0.5 MB,没有外部依赖,也不需要代码生成。与其他库相比,编译后程序大小的差异可能高达 8+ MB(见图表)。
- :rocket: 快速(特别是自 v1.3 起)。它仅使用安全的优化。总会有更快的库存在,但速度只是其中一个因素。如果你重视自己的时间、程序大小和系统可靠性,请选择这个库。
- :lock: 可靠且安全。它通过广泛的测试、覆盖率引导的模糊测试、数据验证以及避免使用 Go 的
unsafe包,来防止恶意 CBOR 数据导致的崩溃。 - :hourglass_flowing_sand: 易用且节省时间。它拥有与 Go 的
encoding/json相同的 API。现有的结构体无需更改。Go 结构体标签如`cbor:"name,omitempty"`和`json:"name,omitempty"`会按预期工作。额外的结构体标签如keyasint和toarray使得 CBOR、COSE、CWT 和 SenML 非常易于使用。
使用 go get github.com/fxamacker/cbor 安装,并像使用 Go 的 encoding/json 一样使用它。
示例:CBOR Web Token (CWT)
keyasint 和 toarray 结构体标签简化了将已签名的 CWT 解码为易于使用的 Go 结构体的过程。这些标签使得解码变得简单:err := cbor.Unmarshal(b, &v)。

对比
建议进行你自己的对比。使用你最常用的消息大小和数据类型。
可能会不时添加额外的对比(特别是速度对比!)。
当前状态
版本 1.x 具有:
- 稳定的 API – 不会进行破坏性的 API 更改。
- 稳定的要求 – 将始终支持 Go v1.12。
- 通过模糊测试 – v1.3 在超过 72 小时的覆盖率引导模糊测试中通过了超过 20 亿次执行。
近期动态
更多关于Golang CBOR库推荐 - 轻量、高效、稳定,恶意数据零崩溃,支持encoding/json API及toarray/keyasint结构体标签 (fxamacker/cbor v1.3)的实战教程也可以访问 https://www.itying.com/category-94-b0.html
我曾使用过这个,很高兴能看到一个经过充分测试的高质量实现! 
更多关于Golang CBOR库推荐 - 轻量、高效、稳定,恶意数据零崩溃,支持encoding/json API及toarray/keyasint结构体标签 (fxamacker/cbor v1.3)的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
Release v1.3 已经完成!它在72小时的覆盖引导模糊测试中通过了超过20亿次执行。
变更内容包括:
- 更快的速度(许多安全优化)
toarray结构体标签keyasint结构体标签- 重构以使用命名和分组内部函数的最佳实践
使用CBOR Web Token (CWT)的示例代码展示了这些标签如何使解码Signed CWT到易于使用的Go结构体变得简单:err := cbor.Unmarshal(b, &v)。
fxamacker/cbor 是一个优秀的CBOR编解码库,完全符合你的需求。它提供了与标准库encoding/json相同的API设计,同时具备轻量、高效、安全的特点。以下是一些关键特性及示例代码:
基本使用示例
package main
import (
"fmt"
"github.com/fxamacker/cbor"
)
type Person struct {
Name string `cbor:"name"`
Age int `cbor:"age"`
City string `cbor:"city,omitempty"`
}
func main() {
// 编码
p := Person{Name: "Alice", Age: 30, City: "New York"}
data, err := cbor.Marshal(p)
if err != nil {
panic(err)
}
fmt.Printf("Encoded: %x\n", data)
// 解码
var p2 Person
err = cbor.Unmarshal(data, &p2)
if err != nil {
panic(err)
}
fmt.Printf("Decoded: %+v\n", p2)
}
使用keyasint标签处理COSE/CWT数据
package main
import (
"fmt"
"github.com/fxamacker/cbor"
)
// 使用keyasint标签处理整数键的CBOR映射
type CWTClaims struct {
Issuer string `cbor:"1,keyasint"`
Subject string `cbor:"2,keyasint"`
Expiry int64 `cbor:"4,keyasint"`
IssuedAt int64 `cbor:"6,keyasint"`
Audience string `cbor:"3,keyasint,omitempty"`
}
func main() {
// 模拟CWT数据
cwtData := []byte{
0xa4, // map(4)
0x01, 0x64, 0x74, 0x65, 0x73, 0x74, // 1: "test"
0x02, 0x66, 0x61, 0x6c, 0x69, 0x63, 0x65, // 2: "alice"
0x04, 0x1a, 0x5f, 0x2e, 0x8f, 0x00, // 4: 1597318800
0x06, 0x1a, 0x5f, 0x2e, 0x8e, 0xc0, // 6: 1597310400
}
var claims CWTClaims
err := cbor.Unmarshal(cwtData, &claims)
if err != nil {
panic(err)
}
fmt.Printf("Issuer: %s\n", claims.Issuer)
fmt.Printf("Subject: %s\n", claims.Subject)
fmt.Printf("Expiry: %d\n", claims.Expiry)
}
使用toarray标签处理紧凑数组格式
package main
import (
"fmt"
"github.com/fxamacker/cbor"
)
// 使用toarray标签将结构体编码为数组
type Point3D struct {
X float64 `cbor:"0,keyasint"`
Y float64 `cbor:"1,keyasint"`
Z float64 `cbor:"2,keyasint"`
}
type CompactData struct {
Name string `cbor:"0,keyasint"`
Points []Point3D `cbor:"1,keyasint,toarray"`
}
func main() {
data := CompactData{
Name: "trajectory",
Points: []Point3D{
{X: 1.0, Y: 2.0, Z: 3.0},
{X: 4.0, Y: 5.0, Z: 6.0},
},
}
encoded, err := cbor.Marshal(data)
if err != nil {
panic(err)
}
fmt.Printf("Encoded size: %d bytes\n", len(encoded))
var decoded CompactData
err = cbor.Unmarshal(encoded, &decoded)
if err != nil {
panic(err)
}
fmt.Printf("Decoded: %+v\n", decoded)
}
处理恶意数据的安全示例
package main
import (
"fmt"
"github.com/fxamacker/cbor"
)
func main() {
// 恶意CBOR数据示例(深度嵌套的数组)
maliciousData := []byte{
0x81, // array(1)
0x81, // array(1)
0x81, // array(1)
0x81, // array(1)
0x81, // array(1)
0x81, // array(1)
0x81, // array(1)
0x81, // array(1)
0x81, // array(1)
0x81, // array(1)
0x81, // array(1)
0x81, // array(1)
0x81, // array(1)
0x81, // array(1)
0x81, // array(1)
0x81, // array(1)
0x81, // array(1)
0x81, // array(1)
0x81, // array(1)
0x81, // array(1)
0x81, // array(1)
0x81, // array(1)
0x81, // array(1)
0x81, // array(1)
0x81, // array(1)
0x81, // array(1)
0x81, // array(1)
0x81, // array(1)
0x81, // array(1)
0x81, // array(1)
0x81, // array(1)
0x81, // array(1)
}
var result interface{}
err := cbor.Unmarshal(maliciousData, &result)
if err != nil {
// fxamacker/cbor会安全地拒绝深度嵌套的恶意数据
fmt.Printf("安全拒绝恶意数据: %v\n", err)
} else {
fmt.Printf("解码成功: %v\n", result)
}
}
性能优化示例
package main
import (
"fmt"
"time"
"github.com/fxamacker/cbor"
)
type SensorData struct {
Timestamp int64 `cbor:"t"`
Values []float64 `cbor:"v"`
DeviceID string `cbor:"d"`
}
func main() {
// 准备测试数据
data := SensorData{
Timestamp: time.Now().Unix(),
Values: make([]float64, 1000),
DeviceID: "sensor-001",
}
for i := range data.Values {
data.Values[i] = float64(i) * 0.5
}
// 编码性能测试
start := time.Now()
encoded, err := cbor.Marshal(data)
if err != nil {
panic(err)
}
encodeTime := time.Since(start)
// 解码性能测试
start = time.Now()
var decoded SensorData
err = cbor.Unmarshal(encoded, &decoded)
if err != nil {
panic(err)
}
decodeTime := time.Since(start)
fmt.Printf("数据大小: %d bytes\n", len(encoded))
fmt.Printf("编码时间: %v\n", encodeTime)
fmt.Printf("解码时间: %v\n", decodeTime)
fmt.Printf("解码验证: DeviceID=%s, Values count=%d\n",
decoded.DeviceID, len(decoded.Values))
}
这个库确实如描述所示,在保持与encoding/json API兼容的同时,提供了CBOR特有的功能标签(keyasint、toarray),并且在安全性和性能方面都有良好表现。编译后的二进制体积小,没有外部依赖,适合对资源敏感和对安全性要求高的场景。



