昨今のComposerは(サプライチェーンアタックについて)どうなってるんすかね??って軽く調べ

PHPユーザーなので、掲題の通り「どうなってるんだろー」って気になったので調べてみました。

きっかけ

やっぱりaxiosの件とか。

blog.flatt.tech

任意のスクリプトの(自動的な)実行について

まず、「postinstall 的な仕組みで色々される」に対しては、「安直にプラグインに自由を与えるな」って話だと思うので、これは2.2でallowed list管理できるようになっておりますな。

blog.packagist.com

composer audit

CVEに対してどう動けるか?的な話の中心になるかな。 composer audit コマンドが追加されたのが2.4。

php.watch

かつ、2.7で強化されてCIフレンドリーな使い方もできたり

Since Composer 2.7, the audit command exits with a non-zero status code if your project relies on abandoned packages.

blog.packagist.com

ref: Switch default audit.abandoned to fail for 2.7 release · composer/composer@e0f7527 · GitHub

2.9になると、「auditコマンドを使って気をつけていれば防ぎやすくなる」から一歩踏み込んで、

Composer now automatically blocks updates to packages with known security advisories.

という挙動の変更が入っている。

blog.packagist.com

※ その後、ちょいちょい事情があってblockしないフラグが導入されている。
cf: New flags to disable/configure blocking by Seldaek · Pull Request #12617 · composer/composer · GitHub

あと、コレで自動ブロックされるのはrequire update 等でパッケージが 更新 される場合かな?という気がする*1
言い換えると、 「既にcomposer.lock がある場合に、 composer install コマンドを実行して、パッケージをDL・展開・配置する」ようなケースでは、ブロックされないのではないか・・?と。

なので、 composer audit コマンドの定期実行をすると良さそう。(もしくは、GitHubとかAWSにスキャンしてくれる機能を使うのかな)

汚染に対して

「意図せず紛れ込んでしまった」ような脆弱性に対する適応は進みつつ、「開発者アカウントの乗っ取り」「悪意のあるコードの埋め込み」は少し意味合いの異なる話になる。
それに、冒頭で言及したaxiosの話とかはコッチのパターンなわけで。

サプライチェーンアタック対策の基本

「既知のもの(パッケージやバージョン)はフィルタリング/ブロック出来るように」と「未知のものはすぐに飛びつかない、遅らせる」で、どうにか感染する確率を下げる・・・っていうのが基本路線なのかなぁというところ。

jxckさんの記事とか参考。 blog.jxck.io

では、検知とか発見って意味での防御と、遅らせるって意味での回避について、Composer/Packagistどうなっているんだろうね〜っていうと、最近割と動きがある。

Transparency

ちょっと前。2.9のタイミングで、(もし怪しい動きがあったとしても)それを検証しやすくする仕組みが入っている*2

blog.packagist.com

Filter

「不審なものがあったら、紛れ込まないようにする」ためのPackagist/Composerの機能の導入。 github.com github.com

Aikido Securityの提供するマルウェアに関する情報提供を取り込んで、「Packagist上で分かるようにする」「Composerが回避する」という機能。

これらのPRを見ていて知ったのだけど、Packagist上で「コイツは汚染されているってフラグが立っているぜーー!」ってUI上にも表示されるようになっていたんだなあ。

techghoshal/my-library - Packagist.org

この辺りが、Composerの次期マイナーバージョンである 2.10 で出るらしく。

なお、今々でリリース候補が出ているっていうホットな状況ですので、見守っていきたいすね

めっちゃ応援しているぞ!

CoolDown

「リリースされてすぐには入ってこないようにする」のやつ。
もしヤベェのが来たとしても、ある程度早急に発見・対応されるだろうという確率論的な話で、「少し期間を置いてからでないと信頼できないよね」を可能にするやつ。

github.com

minimum-release-age というconfigを設定しておくと、リリース後にその指定期間を経過していないパッケージ(バージョン)はrequire/updateの対象から外される(で良いのかな?)

これも 2.10 で・・・・とは行かずに、今のところ2.11 のマイルストーンが設定されている。
というのも、PRを見ながら解決不可能な問題があったから。すなわち、「リリース日時をどう保持するか・誰が管理するか?」というもの。

コメントはココ。
see: https://github.com/composer/composer/pull/12692#issuecomment-4099190463

↓コメントの機械翻訳

この機能についてもう少し考えてみたところ、リリースはパッケージ作成者の管理下にあるため、攻撃者は簡単にリリース日を偽装して過去に設定できてしまうことに気づきました。

そのため、これを実現するには、publish_date のような、パッケージリポジトリのみが所有し、パッケージ側では設定できない新しい日付を設定する必要があると思います。そして、minimum-release-age はその日付(利用可能な場合)に適用されるべきです。これは将来の参考のために書き留めておこうと思っただけです。

そうなんだよなぁ、Packagistが配布するメタ情報には、サーバー側で付与する「公開日時」が無いはず。代わりに、バージョン管理ツールで記された「最終更新日時」はあるんだけど・・・これは改ざん可能ですからね。

「Packagistに登録(更新)された日時」みたいなのを持って、Repository API(=Packagist)でパッケージのメタ情報にクライアントがタッチ不可能なフィールドとしてタイムスタンプを提供すれば良いのかなー?なんて思ったり。

現状+直近でどうしていくか

とりあえず、今できることはこんな感じなのかな

  • 不要なパッケージは外す
    • こんなのはリスクがないんだ、ちゃんとやろう
  • アプリケーションやツールに関しては、 composer.lock をしっかりコミットする
    • composer.json ではバージョン番号までしか指定していなくても*3composer.lock にはsource distの中に "reference": "dca41cd15c2ac9d055ad70dbfd011130757d1f82" のような形でハッシュが入ってくる
    • ライブラリやフレームワークなどは・・どうするんだろうなぁ
    • composer-bin プラグインなどで、「変に広い範囲のバージョン固定/アップデートに巻き込まれにくいようにする」のも、併せて有効なのかな?
  • 関連して、pluginを無造作に信頼しない
    • というか、post-install等のフックでは発火する「無秩序」を最大限しぼっておく
  • composer audit 相当の定期監視を行う
  • (2.10が出たら) Composerを最新化する
    • とりわけ、ここから暫くはマイナー/パッチバージョンでセキュリティ関連の機能強化が増えそうかな〜なんて勝手に思っているので、Changelogに注目しておきたい
  • cooldownほしいね

*1:ちゃんとコード読んでいない、気になる人は調べてください。DeepWikiとかに投げれば一発だろうし

*2:コレはPackagist側の機能であり、Composer云々って感じではない

*3:これだけなら、後から内容を変更できてしまう