Site logo

サプライチェーン対策

サプライチェーン対策

サプライチェーン攻撃って何

コンピュータは0と1で動くが当然ながら0と1でプログラムを書くわけがない。 よって誰かの作った便利ツールを使って良しなに簡単に書くのが通常だ。 しかしその『誰か』が乗っ取られて正規のパッケージとして悪意のある便利ツールを使ってしまったら攻撃が成立してしまう。 特に最近はフロントエンドで使用されている npm というツールで配布されている一部のパッケージが汚染された Shai-hulud というサプライチェーンが猛威をふるっていた。 えるろだは npm を使っている。偶然にも汚染されたパッケージはダウンロードしなかったが対策を打たなければどこかのタイミングで死ぬと考えた。 また、 npm 以外のサプライチェーン攻撃の穴も塞いでおくべきと考えた。

フロントエンド

npm を使っているので危機的である。 今回 npm から pnpm という上位互換ツールに移行し、以下の対策を行った1。なお pnpmnpm に便利なセキュリティ機能を付けたものの認識だ。

  • npm でインストールしてきたときにスクリプトの自動実行を許さない
  • バージョンやハッシュ2の検証と、失敗したらビルドを失敗させる
  • ハッシュが書かれたファイルを必ず使ってインストールする
  • 出て24時間以内のパッケージは使わない
    • 24時間あればTwitterとかのニュースで汚染されているという警告が流れてきて自分も気づいているという想定

Docker

Dockerはいわゆる仮想マシン3と考えてもらってよい。 Dockerはコンテナという仮想マシンの枠組みを使い、どの環境でも同じ環境を再現して環境差による動作の違いを無くしたり、仮に侵害されてもコンテナが動いているマシンに侵害されることができないといった、モダンな開発には欠かせない便利ツールだ。

一般にDockerイメージというものが配布されていてそれを使ってコンテナを建てるが、当然ながら自分の書いたえるろだコードもコンテナに入れ込みたい。よって一般配布のDockerイメージを参照してそれをもとに自分用にカスタマイズして新たなDockerイメージを建てる。

配布されているDockerイメージはバージョン単位で固定していたがハッシュ単位の固定はしていなかった。Dockerイメージを参照する全ての箇所でハッシュを指定することで一意にイメージが定まるようにした。

バックエンド

実はハッシュ単位で固定せずパッケージをインストールしていた。

これはPythonのパッケージと、Kaitai-Struct-Compiler(以下ksc)というyaml形式で書かれたバイナリファイルの定義をPythonコードに変換する4ツールの2つのパッケージだ。

Pythonパッケージはpip-compileによってハッシュ単位の指定をするようにした。

kscはビルド済ツールを apt でインストールしていたがこれでハッシュ指定はつらそうと考えた。そこで自分はソースコードをDockerイメージ作成時にビルドすることにした。

git submodule というものでえるろだのソースコードにハッシュ単位で定まった ksc のソースコードを入れ込み、Dockerイメージ作成時にビルドする。

また、ここで マルチステージビルド という、ビルド用のDockerイメージを作ってさらにそれを使ってDockerイメージを作成するという仕組みを使った。 これにより ksc のビルドだけをするDockerイメージを作り、その ビルドされた ksc を使ってリプレイファイルの定義のコンパイルを行うだけのDockerイメージを作成、それによってできたソースコードのみを最終成果物であるDockerイメージに入れ込むということにした。

これによって最終成果物に ksc 及び ksc を動かすにあたって必要な java が載らないようになった。これで仮に java とかに脆弱性があってバックエンドが動いているときにそれが踏まれる、ということが無くなった。

所感

なんか最近脆弱性とかサプライチェーン攻撃とか出過ぎてるだろ。

AIとかでソースコードを探索させてサクサク脆弱性を見つけては攻撃されて、守る側は後手後手に回る現状。一応それらしい対策は打ったがどこまで持つか…

Footnotes

  1. このブログも pnpm 化による改修を行った。
  2. これが一致していれば0と1の羅列がほぼ一意に定まる。ごくごく稀にハッシュが同じだが違う0と1の羅列が一致するということがあるが、天文学的な確率と考えてもらって構わない。むしろしょっちゅう被ってたらそれは脆弱性と考えてよい。つまりハッシュが一致していれば偽のパッケージとは考えられない。
  3. 正確には違うが一旦簡単のために仮想マシンといった。勿論母艦のカーネルリソースを使ってソフトウェアを動かしているので仮想マシンではないことは理解している。
  4. えるろだはサイレントセレナからリプレイファイルの定義をコピペしている。サイレントセレナでkscを使ってリプレイファイルの構造を定義していたので差異が出ないようにえるろだでもkscを使うようにした。