ペネトレーションしのべくん

さようなら、すべてのセキュリティエンジニア

OSVについて調べてみた

はじめに

Googleがosv-scannerというリポジトリを公開しています。どうやら脆弱性スキャナのようです。

github.com

これを使ってみる前に、OSVとかSBOMとか、知らなかった概念について先に掘り下げて置こうと思います。この記事ではOSVについて見ていきます。

OSV

トップページ曰く「A distributed vulnerability database for Open Source」とのこと。

osv.dev

Aboutでは、OSVは以下のものから構成されると説明しています。

  • OSV Schemaという脆弱性を記述するためのデータフォーマット
  • OSV Schemaで記述された脆弱性情報を集約、参照するためのインフラストラクチャー
    • サイトそのもの
    • API
    • ツール(osv-scannerもここに含まれる?)

OSV Schema

OSV Schemaがどんな感じか見てみることにします。

ossf.github.io

Aboutによると、OSV Schema策定にあたっての課題意識のひとつとして、各エコシステムでのパッケージの命名およびバージョニングとCPEを照合するのって難しいよね、というのがあるようです。

Enforces version specification that precisely matches naming and versioning schemes used in actual open source package ecosystems. For instance, matching a vulnerability such as a CVE to a package name and set of versions in a package manager is difficult to do in an automated way using existing mechanisms such as CPEs.

CPEという仕組み自体が結構きついよね、という話を以前フォロワーさんとした記憶があって、掘り返してみたらやっぱり嘆いてました。もっとも、今見返すと無意識的にプロプライエタリな製品について言及していたと思うので、このOSVのスコープ外ですかね。なんてったって「Open Source Vulnerabilities」だし。

OSV Schemaは、以下のような情報を含んでいます。

  • 脆弱性情報の公開日や更新日
  • 要約と詳細
  • 影響を受けるパッケージ
  • 参考URL
  • 重大度

severity

重大度を示す severity[]type というフィールドを持ち、これは執筆時点で CVSS_V2 もしくは CVSS_V3 の値をとることが想定されています。

ossf.github.io

そのうちEPSSとかも入ってくるんですかね?

www.first.org

また、このスキーマはありものの脆弱性情報の効率的な記述方法を提案するものであって、CVSSにとって代わるような新たな脆弱性評価手法を提案するものではないことが分かります。

affected

各パッケージへの影響範囲を示す affected[] は、以下の情報から構成されます。

  • package
  • ranges
  • versions
  • ecosystem_specific
  • database_specific

package

脆弱性の影響を受けるパッケージに関する情報です。以下の値を持ちます。

  • ecosystem: エコシステム名。 Go とか npm とか。
  • name: パッケージ名。
  • purl: purl-specという標準に則った、パッケージのURI。オプション。

purl-specというのは初耳でした。これもエコシステムによってパッケージの命名規則を統一することで参照しやすくしようというのがねらいのようです。

github.com

ranges

以下の値を持ちます。

  • type: indtoduced および fixed で使うバージョンの表現方法。
    • SEMVER: SemVer 2.0.0 に則ったバージョン表記。
    • ECOSYSTEM: 各エコシステムに則ったバージョン表記。
    • GIT: Gitのコミットハッシュ。
  • repo: パッケージのコードリポジトリのURL。affected[].ranges[].typeGIT の時は必須。
  • events[]: 脆弱性の各イベント(発生、修正など)に関する情報。
    • introduced: 脆弱性が発生したバージョン。
    • fixed: 脆弱性が修正されたバージョン。
    • limit: 上限。ってなんだ……??

versions

脆弱性があるパッケージバージョンのリストです。 affected[].ranges と役割が重複している感じがしますが、脆弱性があるバージョンを列挙してあるとぱっと見分かりやすいよねぐらいのフィールドなんだと勝手に解釈しています。

例えば、Log4Shellに該当するJSONファイルを見てみると、 affected.version がありません。

github.com

しかしosv.devで同じ脆弱性のページを見てみると、(JSONaffected.version はないのに)Affected versionsとして値がマッピングされていることが分かります。

osv.dev

後述する参考実装でも、rangesとversionsの両方を評価する実装になっているので、やはり意味合い的に重複するものみたいです。

affected[] による脆弱性評価

OSVで記述された脆弱性情報を用いて脆弱性評価をするコードの参考実装が紹介されていました。メインルーチンである IsVulnerable() だけ読んでみると、以下のようなロジックになっています。

  • 検査対象であるパッケージが affected.package と同一だったら次のチェックをする
    • 検査対象バージョンが affected.versions に含まれているか、affected.ranges に含まれていたら脆弱性あり
  • いずれにも該当しなければ脆弱性なし
func IsVulnerable(pkg, v, osv)
  for affected in osv.affected
    if affected.package == pkg
      if IncludedInVersions(v, affected.versions) ||
           IncludedInRanges(v, affected.ranges)
        return true

  return false

疑問点

参考実装では pkgosv.affected[].package を直接比較していますが、 これを成立させるために pkg をOSV形式に直すのって実は地道な努力が必要だったりしないか?と思うなどしました。それこそosv-scannerのソースを読めば解決しそうですが、それはまた次のお話ということで。