TT Lab
はじめる
学ぶ 学習パス コース

ビルドは緑だったのに、あのライブラリを入れたのは誰か

赤い行6件のうち、今日直せるのはどれか

TT Labで続きを見る

一言でいうと

スキャン結果を役に立つものにするのは、深刻度ではなく、2つの判定です。このバージョンが本当にその区間に入るのか、そして修正バージョンがあるかの2つです。

なぜ必要なのか

脆弱性スキャナーを初めて動かすと、赤い行が数百個出ます。その一覧をそのまま開発チームに送っても、何も起きません。全部は直せないことを、送る人も受け取る人も知っているからです。すると、一覧は添付ファイルとして残り、翌月にもう一度作られ、また何も起きません。

減らせる場所は2か所だけです。1つ目は誤検知です。すでに修正されたバージョンを使っているのに引っかかって出てくると、1、2件混ざるだけで、一覧全体の信頼が崩れます。「前にも違うと言ったじゃないですか」が一度出ると、それ以降は誰も開かなくなります。2つ目は修正バージョンがあるかどうかです。上げるバージョンが出ていれば、今日上げれば済むことで、まだなければ、緩和策と期限を書いて見守ることです。この2つは性格がまったく違う作業なのに、深刻度だけで並べると、同じ欄に混ざります。

どう動くのか

脆弱性データを機械が読める形で書く形式が、OSVスキーマです。核心はaffected配列で、その中のrangesがバージョンのタイムラインを書きます。各events項目は、次の4つのうち1つです。introduced(ここで入ってきた)、fixed(ここで修正された)、last_affected(ここまでは影響を受けると確認された)、limit(ここまでだけを見る)です。ドキュメントは、1つのイベントオブジェクトに種類を2つ入れることを明示的に禁止し、events配列にはintroducedが少なくとも1つ必要だと書いています(OSVスキーマ)。

ここで実務者がよく間違えるところが3つあります。

경계        구간은 introduced 이상 fixed 미만이다.
            fixed 와 같은 버전은 이미 고쳐진 것이라 걸리면 안 된다.

last_affected  fixed 가 없을 때 쓰는 천장이라 그 값 **자체는 아직 영향받는다.**
            경계의 포함 여부가 fixed 와 반대다. 문서는 가능하면 fixed 를 쓰라고
            강하게 권한다 — last_affected 는 거짓 음성을 만들 여지가 있다.

여러 구간    한 권고에 구간이 둘 이상일 수 있다. 1.x 에서 고쳐지고 2.1 에서 다시
            들어온 경우가 그렇다. 첫 구간만 보고 끝내면 판정이 뒤집힌다.

このコードブロックの韓国語の行は、順に、区間はintroduced以上fixed未満で、fixedと同じバージョンはすでに修正されたものなので引っかかってはいけない、last_affectedはfixedがないときに使う上限なのでその値自体はまだ影響を受け、境界の含み方がfixedと逆であり、ドキュメントは可能ならfixedを使うよう強く勧めていて、last_affectedは偽陰性を生む余地がある、1つのアドバイザリに区間が2つ以上ありうるので、1.xで修正されて2.1で再び入った場合のように、最初の区間だけを見て終えると判定が覆る、という意味です。

さらに、バージョンの比較自体が落とし穴です。OSVのSEMVER範囲の種類は、先頭にvのないSemVer 2.0の順序に従うよう書いていますが、文字列で比較すると、"1.9.0"が"1.10.0"より大きいと出ます。桁ではなく数字を見比べる必要があります。エコシステムがSemVerを強制しない場合のために、ECOSYSTEMの種類が別にあり、そのときの並べ替えのルールは、エコシステムごとに違います。

最後に、どこに載って出ていくのかを分ける必要があります。CycloneDXは、コンポーネントのscopeでこれを表現し、実行時の呼び出し経路に届かないものをexcludedと書きます(CycloneDX 1.6 JSON)。同じ深刻度でも、デプロイの成果物に載るものと、ビルドマシンで終わるものは、別の話です。

現場での姿

最もよく見る失敗は、ウェイバー(waiver)が万能キーになることです。最初は「今は直せないので、期限を書いて先に進もう」で始まりますが、数か月たつと、修正バージョンがあるものまでウェイバーで通すようになります。そうすると、ゲートはその日から飾りです。ウェイバーは直せないものにだけ与え、期限と担当者と緩和策を必ず一緒に書いて初めて、その性質が保たれます。

2つ目は、基準日をdateで読むことです。ウェイバーの期限切れを今日の日付で判定すると、昨日通ったビルドが今日失敗します。それ自体は正しい動作ですが、再現が必要な検査では、基準日を入力として受け取って初めて、同じ入力に同じ答えが出ます。

3つ目は、データが静かに古くなることです。エアギャップ環境では、脆弱性データを社内にミラーして使いますが、ミラーが止まったことに気づく仕組みがないと、スキャンは緑を出し続けます。引っかかるものがないから緑なのか、データが3か月前のものだから緑なのか、区別がつきません。そのため、データに生成時刻を書いておき、ゲートがその時刻も一緒に見るようにするほうが安全です。

そして、もう1つあります。スキャナーが「影響を受ける」と言ったことと、「悪用可能」は違います。欠陥のある関数を私たちが一度も呼んでいなければ、実際のリスクは低いです。この区別を機械が読める形で書く形式がVEXで、CycloneDXは、脆弱性の情報とその悪用可能性を、BOMの中で一緒に表現できるようにしています(CycloneDXの概要)。ただし、この判断は人がコードを読んで初めて出るものなので、一覧が整理される前に手を付けると、時間を使うだけです。

次のラボですること

バージョン比較器を自分で作って境界値を通し、OSVのタイムラインどおりに照合して、実際に引っかかるものだけを選び出します。そのあと、「修正バージョンがあるか」と「ユーザーに届くか」の2つの軸で分けて、ポリシーゲートをプログラムとして書き、ウェイバーがどこまで通用すべきかを、コードで固定します。