Skip to content

🔄 CPE 2.2 与 2.3

CPE 历史上出现过两种官方字符串格式。CPE 2.2 是较老的 URI 风格;CPE 2.3 是取代它的较新 格式化字符串 风格。两者在真实数据中都还会出现——NVD 历史上输出 2.2 URI,而现代字典和 CVE 数据使用 2.3——因此一个健壮的工具必须两者都能处理。

两种语法

CPE 2.2 URI(11 个概念字段塞进 7 个 URI 槽位):

cpe:/a:apache:http_server:2.4.58
cpe:/o:microsoft:windows:10:enterprise

CPE 2.3 格式化字符串(13 个字段,冒号分隔,前缀 cpe:2.3:):

cpe:2.3:a:apache:http_server:2.4.58:*:*:*:*:*:*:*
cpe:2.3:o:microsoft:windows:10:*:en-US:*:enterprise:*:*:*

字段对比

概念2.2 URI 位置2.3 字段编号说明
part11a / o / h
vendor22
product33
version44
update55
edition662.3 把它拆成 4 个子字段
language77
software edition打包进 edition8仅 2.3 可表达
target software打包进 edition9仅 2.3 可表达
target hardware打包进 edition10仅 2.3 可表达
other11仅 2.3 可表达

关键区别:2.3 能把 sw_editiontarget_swtarget_hwother 表达为独立字段,而 2.2 把它们塞进单个 edition 槽位。这意味着 2.3 名称的表达能力严格强于 2.2 URI。

两者互转

因为 2.3 携带更多信息,2.3 → 2.2 方向是有损的:四个额外字段会被折回 edition。2.2 → 2.3 方向则只需把缺失字段填为逻辑值 *(ANY)。

go
package main

import (
    "fmt"
    "github.com/scagogogo/cpe-skills"
)

func main() {
    // 2.3 -> 2.2
    uri22, err := cpeskills.ConvertFSToURI("cpe:2.3:a:apache:http_server:2.4.58:*:*:*:*:*:*:*")
    if err != nil { panic(err) }
    fmt.Println(uri22) // cpe:/a:apache:http_server:2.4.58

    // 2.2 -> 2.3
    fs23, err := cpeskills.ConvertURIToFS("cpe:/a:apache:http_server:2.4.58")
    if err != nil { panic(err) }
    fmt.Println(fs23) // cpe:2.3:a:apache:http_server:2.4.58:*:*:*:*:*:*:*
}

该用哪个?

  • 读取时两者都要支持——输入数据可能含任意一种。
  • 写出时优先 2.3——它无歧义且是当前标准。
  • 不在意输入是哪种形式时用 MustParse

与各模块的关系

  • Parser 2.2 —— ParseCpe22FormatCpe22
  • Parser 2.3 —— ParseCpe23FormatCpe23
  • Binding —— ConvertURIToFSConvertFSToURI

小结

2.2 是遗留但无处不在;2.3 表达力强但冗长。把它们当作同一逻辑名的两种序列化,自由互转,并为新产出物优先选用 2.3。

Released under the MIT License.