Slide 1

Slide 1 text

5分で問診! Composer セキュリティ健康診断 PHPカンファレンス2026 Akito Tsukahara

Slide 2

Slide 2 text

自己紹介 塚原 彰仁 @AkitoTsukahara 株式会社コドモン ソフトウェアエンジニア 2歳の息子とトイプードルの父。 2014.10 学生の頃に初のPHPカンファレンスに参加 2026.07 人生で7回目のPHPカンファレンス 2

Slide 3

Slide 3 text

OSSサプライチェーン攻撃とは コードを直接攻撃せず、 信頼されたパッケージを乗っ取る攻撃 3

Slide 4

Slide 4 text

OSSサプライチェーン攻撃とは パッケージinstallを実行しただけで、 コード変更なし・ユーザー操作なしで感染 4

Slide 5

Slide 5 text

axios npm サプライチェーン攻撃(2026/3/31) アカウント乗っ取りによる不正なバージョンを公開 被害規模 ● 週次1億ダウンロードの人気パッケージが、わずか3時間で世界中に拡散 ● 実害を受けた可能性のある規模:数百〜数百万ユーザー(Microsoft推定) 5

Slide 6

Slide 6 text

PHPエコシステムでも発生(2026年4月〜5月) ● intercom/intercom-php(2026/4/30) ○ Mini Shai-Hulud(TeamPCP)による組織的攻撃の一部として PackagistのGitタグを改ざん ● laravel-lang(2026/5/22-23) ○ 漏洩したGitHub PATを悪用し、4リポジトリで700件超のGitタ グを改ざん 6

Slide 7

Slide 7 text

皆さんは対策できていますか? 󰳋🩺

Slide 8

Slide 8 text

この診断に、絶食は不要です。 その場での挙手🙋も不要です ⚠ 挙手すると、インシデントとして扱われる可能性が...🙅 8

Slide 9

Slide 9 text

開発フローと防御ポイント ①取り込む前 ②取り込む時 ③使っている間 選定・検証 インストール 制御・監視 ⓪前提:Composer自体を最新に保つ 9

Slide 10

Slide 10 text

問診① ⓪前提 Composerのバージョンは 最新ですか? 10

Slide 11

Slide 11 text

処方① ⓪前提 composer self-update で更新する Composer自体のRCE脆弱性(CVE-2026-40176等)/ 2.10のマルウェア検知・タグ改ざん防止は最新版のみ 11

Slide 12

Slide 12 text

問診② ①取り込む前 公開直後のパッケージ、 いきなり入れてませんか? 12

Slide 13

Slide 13 text

処方② ①取り込む前 クールダウンを設定して、 公開直後の数日は様子見を 悪意のあるリリースの多くは数分〜数時間で検知される →数日待つだけでも大半を回避できる 13

Slide 14

Slide 14 text

処方② ①取り込む前 Renovateの例: “minimumReleaseAge”: “3 days” Dependabotの例: cooldown: default-days: 7 # 未設定だと3日 これが効くのは自動更新の経路だけ 手元で追加する時には注意が必要 14

Slide 15

Slide 15 text

おまけ:コドモンでの取り組み Lefthookで公開直後パッケージをコミット前にチェック 手動追加におけるクールダウンチェックをカバー git commit Lefthook lock差分を抽出 公開日をチェック パッケージの 更新 pre-commit フックで起動 追加・更新 パッケージを特定 公開直後なら 警告⚠ ⚠ 公開日チェックに利用しているpublished_atが改ざんされたら防げない🙅 15

Slide 16

Slide 16 text

問診③ ②取り込む時 composer.lock リポジトリにコミット していますか? 16

Slide 17

Slide 17 text

処方③ ②取り込む時 composer.lock をコミットし、 composer install で運用 依存関係の再現性と改ざん検知のため laravel-lang事例:同一バージョン番号のまま中身だけ差し替え→lock固定+installなら防げた 17

Slide 18

Slide 18 text

composer.lockの役割(1/2) composer.lockなしの場合 composer.json “pkg”: “^1.0” install 7/20 7/21 7/22 v 1.0.2 v 1.0.3 v 1.0.3 💀 installする度にバージョンが変化する 改ざんされたバージョンを取り込んでしまうリスクがある 18

Slide 19

Slide 19 text

composer.lockの役割(2/2) composer.lockありの場合 composer.lock “asdf123” install 7/20 7/21 7/22 v 1.0.2 asdf123 v 1.0.2 asdf123 v 1.0.2 asdf123 毎回同じ中身が取り込まれる CI経由でのinstallでも問題なし(バージョン偽装も防げる) 19

Slide 20

Slide 20 text

問診④ ②取り込む時 composer install に --no-scripts --no-plugins 付けてますか? 20

Slide 21

Slide 21 text

処方④ ②取り込む時 installでは、依存側のスクリプトを実行させない composer install --no-scripts --no-plugins ⚠ 何にでも付ければ良い訳ではない Laravel等は package:discoverが必要。必要なスクリプトだけ後から明示的に実行する 21

Slide 22

Slide 22 text

問診⑤ ③使っている間 CIで composer audit、 実行していますか? 22

Slide 23

Slide 23 text

処方⑤ ③使っている間 CIパイプラインに composer audit を組み込む(検知したら落とす) composer audit --format=summary || exit 1 audit.block-insecure(2.9~)はupdate / require時のみ有効 23

Slide 24

Slide 24 text

詳細チェックリスト ⓪前提 ◻ Composer自体を最新に保つ ⭐ ①取り込む前 ◻ 公開直後の版をすぐに取り込まない ⭐ ◻ 依存追加の前にパッケージの素性を確認 ◻ (組織)取り込み窓口の一元化・ミラー経由 ②取り込む時 ◻ composer.lock をコミット ⭐ ③使っている間 ◻ CI でcomposer auditを実行 ⭐ ◻ プルリクで composer.lock の差分をレビュー ◻ 脆弱性発見から一定時間内に更新するルール ◻ 上流が直らない場合の代替手段(フォーク等) 番外編(CI/CD) ◻ CI に渡すクレデンシャルの最小権限化 ◻ CI/Docker での非root実行 ◻ allow-plugins を許可リスト化 ◻ CIで --no-scripts --no-plugins ⭐ ⭐=本編で紹介した項目 24

Slide 25

Slide 25 text

Web問診票を用意しました!チェックしてみよう https://akitotsukahara.github.io/composer-health-check/ 25

Slide 26

Slide 26 text

Web問診票を用意しました!チェックしてみよう https://akitotsukahara.github.io/composer-health-check/ 26

Slide 27

Slide 27 text

定期的な診断もお忘れなく 💊

Slide 28

Slide 28 text

No content

Slide 29

Slide 29 text

付録💊

Slide 30

Slide 30 text

付録|取り込み窓口の一元化(組織向け) ①取り込む前 Packagist.org に直接アクセスしていますか? Private Packagist等のミラーを経由すると: ● マルウェア版のダウンロードを組織全体でブロック(古いComposerでも有効) ● 依存パッケージが削除されてもビルド継続可能 参考:Blocking malware downloads for every Composer version in Private Packagist 30

Slide 31

Slide 31 text

付録|composer.lock 差分のレビュー ③使っている間 プルリクで composer.lock の差分、見てますか? ● 意図しないパッケージの追加・バージョン変更に気づける最後の目視ポイント ● 「なぜこの間接依存が増えた?」に答えられるか lockが守れるのはinstall時のみ update時の差分レビューが、改ざん参照を持ち込む前の最終防衛 laravel-lang事後調査でも、lockのSHAを上流履歴と突き合わせる方法が感染判定手段に 31

Slide 32

Slide 32 text

付録|audit.block-insecure の補足 audit.block-insecure は Composer 2.9からデフォルトで true ● update/require/remove の依存解決時のみ有効 ● composer install には適用されない(lockの再現性維持のため意図的な仕様) なので CIでの composer audit 必須化でカバーする 既知の脆弱性があるバージョンは依存解決の時点で弾かれるが、 lockファイルからのinstallは素通りする 32

Slide 33

Slide 33 text

付録|minimum-release-age の現状 ①取り込む前 Composer に minimum-release-ageは 現状未実装 ● 依存ポリシーの基盤は Composer2.10 で追加済み、cooldownは追加予定 ● published_at メタ情報を改ざん不可能にする前提作業の完了後に実装見込み それまでは Dependabot/Renovateのクールダウン設定で代替 npm等の他エコシステムには既に存在する機能 参考:An update on Composer & Packagist supply chain security 33

Slide 34

Slide 34 text

参考リンク ● CVE-2026-40176(Composer Perforceコマンドインジェクション) ● Composer & Packagistサプライチェーンセキュリティ最新状況 ● Composer 2.10リリース(マルウェア検知・タグ改ざん防止) ● Composer 2.9.6リリースノート(CVE-2026-40261/40176修正) ● Composer 2.9リリース(audit.block-insecure) ● audit.block-insecureの適用範囲(update/require時のみ) ● intercom-php侵害の詳細(Composerプラグイン化) ● intercom-php GitHub Security Advisory ● intercom-php:プラグイン化手口の一次分析(Socket) ● laravel-lang侵害の詳細(Snyk Advisory) 34

Slide 35

Slide 35 text

参考リンク ● laravel-lang:lock固定+installで影響なしの分析(StepSecurity) ● laravel-lang:lockのSHA監査による感染判定手順(Mend) ● axios npmサプライチェーン侵害(CISA Alert) ● axios事件のポストモーテム(axios公式GitHub Issue) ● axios事件の技術分析(Microsoft Security Blog) ● OpenSSF S2C2F 公式仕様 ● Packagist:安定版バージョンの不変化(immutable versions) ● Private Packagist:マルウェアダウンロードブロック ● Private Packagist:ミラーリング機能 35

Slide 36

Slide 36 text

No content