今日は雨の日曜日・・・6/1に提供されたが6/5には提供禁止となってしまった、現在最高性能を持つというClaude Fable5が7/1から再び提供されて、7/7まで使えるという・・・これは、是非とも一番課題で問題が多いシステム全体の成熟性を確認しなければ、熱も下がって少し調子も上がったので、さっそく取り掛かる

0.前提条件

  • まずFable5には修正・削除・リファクタリングは一切行わなず検証を実施する
  • 対応済みの事項は以下の内容(再確認は必要)
  • AuthorizesTenantAccessトレイトによるコントローラのテナント認可
  • SecurityHeadersMiddleware、HTTPS 強制、セッション強化、不審ログイン検知
  • CSP 対応の途中経過(インラインイベントハンドラの addEventListener 化、@alpinejs/csp 採用)

1.作業フェーズ

  • フェーズ1: セキュリティ検証(ファイル別)
  • フェーズ2: 保守性・コード品質の改善提案(全体)
  • フェーズ3: バグおよびバグの可能性の検出(全体)

2.フェーズ1: セキュリティ検証

2-1. 検証観点(チェックリスト)

A. テナント分離(最優先)

  • クエリに tenant_id 等のスコープ漏れがないか(Eloquent 直接呼び出し、find($id)、DB:: 生クエリ含む)
  • AuthorizesTenantAccess トレイトの適用漏れコントローラ・メソッド
  • ルートモデルバインディングでの他テナントリソース参照可能性(IDOR)
  • グローバルスコープの回避箇所(withoutGlobalScopes 等)の妥当性

B. 認証・認可

  • ミドルウェア(auth, verified 等)の適用漏れルート
  • Policy / Gate 未適用のまま操作可能なアクション
  • 権限昇格の可能性(ロール判定の抜け)

C. 入力検証・インジェクション

  • バリデーション未実施・不十分なリクエスト処理
  • SQL インジェクション(whereRaw, DB::raw, DB::select 等の変数連結)
  • マスアサインメント($fillable/$guarded の不備、$request->all() の直接渡し)
  • パストラバーサル(ファイルパスにユーザー入力を使用している箇所)

D. XSS・出力エスケープ

  • Blade の {!! !!} 使用箇所の妥当性
  • SVG ダイアグラムエディタ(約3,600行の JS): ユーザー入力の SVG/DOM への挿入方法(innerHTML、属性直接代入等)、保存された SVG データの再表示時のサニタイズ
  • リッチテキストバー(RTB)経由の HTML 挿入のサニタイズ

E. CSP 対応

  • 残存するインラインイベントハンドラ(onclick 等)・インライン script/style
  • SecurityHeadersMiddleware の CSP ディレクティブの妥当性(unsafe-inline / unsafe-eval の残存有無)

F. CSRF・セッション・Cookie

  • CSRF 保護の除外ルート($except)の妥当性
  • Ajax/fetch 呼び出しの CSRF トークン付与漏れ
  • セッション・Cookie 設定(secure, httponly, samesite)と Xserver リバースプロキシ構成(TrustProxies)との整合

G. ファイルアップロード

  • 拡張子・MIME タイプ検証、サイズ制限
  • 保存先(public 直下への保存有無)、実行可能ファイルの拒否
  • ダウンロード時のテナント認可

H. 情報漏洩

  • ログ・例外メッセージへの機密情報出力
  • .env 値のハードコード、デバッグコードの残存(dd, dump, console.log の機密出力)
  • API レスポンスの過剰な属性返却(Resource 未使用でのモデル直接返却)

I. 依存パッケージ

  • composer audit および npm audit を実行し、既知脆弱性を報告する(アップデートは実施しない)

3.フェーズ2: 保守性・改善提案

3-1. 検証観点
  • 重複コード: コントローラ・JS 間の重複ロジック(サービスクラス / 共通モジュールへの抽出候補)
  • 肥大化: 長大なコントローラメソッド・Blade ファイル・JS ファイル(特に SVG エディタ約3,600行の分割方針)
  • 命名・構成: Laravel 標準構成からの逸脱、命名の不統一(日本語/英語混在の規則性含む)
  • 設定のハードコード: config/env に逃がすべきマジックナンバー・文字列
  • テスト: 自動テストのカバレッジ状況、テナント分離・認可まわりのテスト欠落箇所
  • フロントエンド: Blade 内 JS の構造(モジュール化、イベント委譲の一貫性、Alpine.js との役割分担)
  • DB: マイグレーションとスキーマの整合、インデックス欠落(tenant_id 複合インデックス等)、N+1 クエリ
  • ドキュメント: CLAUDE.md / README の実態との乖離

4.フェーズ3: バグおよびバグの可能性

4-1. 検証観点
  • 明確なバグ: 未定義変数・null 参照、型不整合、到達不能コード、条件式の誤り(=/==/=== 等)
  • JS 側: SVG エディタのイベントリスナー解除漏れ(メモリリーク)、tblMergeCells/tblSplitCell 等テーブル操作の境界条件、undo/redo の状態不整合、非同期処理の競合
  • 境界条件: 空配列・null・0件データ時の挙動、日付境界(年度・和暦処理があれば特に)
  • トランザクション: 複数テーブル更新時のトランザクション欠落、失敗時のロールバック不備
  • 並行性: 同一テナント内の同時編集での上書き・競合(楽観ロックの有無)
  • 環境差異: MariaDB(ローカル)と MySQL(本番)の差異に起因する潜在問題、Xserver 固有設定への依存
  • エラー処理: try-catch の握りつぶし、失敗時にユーザーへ誤った成功表示をする箇所

5.実行手順

  1. リポジトリ構成を把握する(app/, routes/, resources/views/, resources/js/, database/, config/, public/ を中心に全体を読む。vendor/, node_modules/ は除外)
  2. フェーズ1を実行し、レポートを出力して停止・確認を待つ
  3. 承認後フェーズ2を実行し、レポートを出力して停止
  4. 承認後フェーズ3を実行し、レポートを出力して完了報告
  5. 各フェーズの完了報告には「検証したファイル数」「読み飛ばした箇所とその理由」を必ず含める(検証の網羅性を判断できるようにするため)

F1.セキュリティ検証レポート(フェーズ1)

F1-1.検証規模
  • コントローラ: 約40ファイル / モデル: 約50ファイル / Blade: 約168ファイル / ルート: 3ファイル / サービス: 8ファイル
  • 検証観点: A テナント分離 / B 認証・認可 / C 入力検証・インジェクション / D XSS / E CSP / F CSRF・セッション / G ファイルアップロード / H 情報漏洩 / I 依存パッケージ
F1-2.指摘件数(重大度別)
主な内容
Critical7クロステナント IDOR 群(工程表・安全パトロール・RA・施工計画書)、CSP unsafe-inline + 保存型XSS の複合、phpspreadsheet SSRF/RCE
High12テンプレート認可欠落、機密ファイルの public 保存、保存型XSS(図面/AI-HTML/style属性)、依存パッケージ High、-tmp/_old ファイルのオートロード混入
Medium15Mass Assignment、例外メッセージ露出、グローバルマスタ越境、パストラバーサル、Secure Cookie 未設定 等
Low多数多層防御・推奨改善(代表例+件数で集約)
F1-3.総評
  • 全モデルにテナント用グローバルスコープ(BelongsToTenant 等)が存在せず、テナント分離は各コントローラの手動 authorizeProject() に全面依存している。
  • そのうえ authorizeProject() は「Project が自社か」しか見ず、ネストした子リソース(schedule / patrol / riskAssessment / item)の親一致を検証していないメソッドが多数あり、Route::scopeBindings() も未使用。結果として「自社の Project ID + 他社の子リソース ID」を URL に並べるだけで他テナントのデータを閲覧・改ざん・削除できる Critical な IDOR が7系統存在する。
  • 加えて CSP に script-src ‘unsafe-inline’ が残存し、図面ノード・AI整形HTMLがサーバー側サニタイズなしで保存・再表示されるため、保存型XSSが現実的に成立する。

一方で、認可が正しく実装されているコントローラ群も多く(ProjectPlan / Audit 系 / CompanyAdmin など)、修正パターンは「authorizeProject() の追加 + 子リソースの親一致 abort_if の2行」と明確です。恒久対策として Route::scopeBindings() の全面適用とグローバルスコープ導入を行えば、監査耐性は大きく向上します。

F2.保守性・改善提案レポート(フェーズ2)

F2-1.テナント設計の未完了モデル洗い出し

重要な前提: 本アプリには BelongsToTenant 相当のグローバルスコープ(addGlobalScope)は1つも存在しない。テナント分離はすべてコントローラ内の手動 where(‘company_id’, …) / authorizeProject() に依存している。既存の booted()(BarTask / NetworkNode / NetworkArrow)は front_id(UUID)採番専用でスコープではない。したがって下表の「グローバルスコープ」列は全モデル「未実装」。

テナント到達経路: 子テーブルは company_id を持たず、project_id → projects.company_id(または schedule_id → schedules.project_id、audit_report_id → audit_plans.company_id 等)の多段リレーションでのみテナントを特定できる。

F2-2.観点: 重複コード
  • 【高】Anthropic API 呼び出しの8重複(CLAUDE.md「AI推論は共通コード」ルール違反)
  • 【高】テナント認可の二重方式(トレイトがあるのに手書きが残存)
  • 【中】★ CSV入出力ロジックの6重複
  • 【中】Docx/Xlsx出力の二系統併存(デッドコードの懸念)
  • 【中】フロントエンド fetch/CSRF/モーダル制御の重複
F2-3.観点: 肥大化

コントローラ行数 Top10(実測)

ファイル
1548ConstructionPlanController.php
952ProjectPlanController.php
865NetworkScheduleController.php
687SafetyPatrolController.php
573EnvironmentController.php
432RiskAssessmentController.php
392BarChartController.php
350ChecklistController.php
313UserController.php
251CompanyAdminController.php

【高】Blade巨大ファイル(インラインJS肥大)

ファイル特記
3082schedules/network.blade.php単一<script> が724-3080の約2356行
2439schedules/barchart.blade.php同様の巨大インラインJS
1875projects_plan/edit_section.blade.php@push(‘scripts’)+diagram-editor-script include+openCtxMenu上書きIIFE
854environment/edit_environment.blade.php
729projects_plan/setup.blade.php対応 setup.js(392行)は分離済み=良い前例
  • 提案: network / barchart の巨大インラインJS を resources/js/schedules/network.js・barchart.js に外部化(setup.js の前例に倣う)。CSP unsafe-inline 除去の前提条件でもある。
  • 想定作業量: 大 → 別途計画が必要

【中】SVGダイアグラムエディタ群(実測 計4172行)の再分割
既に責務別5分割済み(良い設計)だが個別ファイルが肥大:

ファイル責務
1541diagram-editor-nodes.blade.phpノードCRUD/RTB/画像/線ノード
1132diagram-editor-table.blade.php表/Excel貼付/xspreadsheet
726diagram-editor-ui.blade.php右クリック/保存/ページ/テンプレ/印刷
602diagram-editor-connect.blade.phpコネクタ/接続線ダイアログ
154diagram-editor-core.blade.php状態/Undo-Redo/グリッド
F2-4.観点: DB(マイグレーション/スキーマ)
  • 【高】★ projects.company_id にインデックスが無い
  • 【高】★ StylePreset / AiFormatPreset のテナント未分離
  • 【中】★ login_logs.company_id に索引無し
  • 【中】★ 空モデル ChecklistResult / SafetyJudgment
  • 【中】N+1 の温床
  • 【低】その他、データ補正マイグレーション(repair_section_names 等)の down() が非可逆(運用上許容範囲)、同一タイムスタンプのマイグレーション複数(実行順が名前順依存。以後は一意タイムスタンプ推奨)
F2-5.観点: 命名・構成 / 設定のハードコード
  • 【中】★ role の数値マジックナンバー(1/5/2)が定数化されていない
  • 【中】★ config/anthropic.php の拡張
  • 【中】★ コントローラ変数のキャメル/スネーク混在(CLAUDE.md規約違反)
  • 【低】★ 外部URLのベタ書き
  • 【低】★ Services のクラス名サフィックス不統一
  • 【中】routes/web.php が個別定義中心(400行超)
F2-6.観点: テスト
  • 現状、意味のある独自テストは tests/Feature/TenantIsolationTest.php の1本(27ケース)のみ。Project / SafetyPatrol / Checklist・Evidence / ConstructionPlan(旧版)/ Environment / RiskAssessment の他社IDORを403で網羅検証しており良質。role=1 の越境許可も検証済み。tests/Feature/Auth/*(5本)・ProfileTest は Breeze 標準。ExampleTest(Feature/Unit) はスケルトンのまま。tests/Unit/は実質ゼロ。phpunit.xml は sqlite :memory:+RefreshDatabase で正常に機能。
  • 【高】★ テナント分離テストの網羅漏れ(IDOR観点で最重要)・・tests/Feature/TenantIsolationTest.php(拡充)
  • 【低】★ スケルトンテストの削除・置換
F2-7.観点: ドキュメント
  • 【中】★ README.md が Laravel 標準テンプレートのまま(実態と乖離)
  • 【低】★ CLAUDE.md「変数はスネークケース」が実態と乖離
  • CLAUDE.md セキュリティ記録の実態整合 — 概ね正確(確認済み)
F2-10.大規模リファクタリング候補(別途計画が必要)
  • BelongsToTenant グローバルスコープ導入(テナント設計の恒久策・フェーズ1 Critical群の根本対策)
  • AnthropicClient 抽出(AI呼び出し8重複の集約+config化)
  • ConstructionPlanController 4分割(1548行)
  • schedules network/barchart のJS外部化(各2,000行級)
  • diagram-editor モジュール化(約4,150行のグローバルスコープ解消)
  • Docx/Xlsx 二系統の一本化(デッドコード380行撤去、要機能等価検証)
  • フロントエンド共通JS(apiFetch/modal)導入(59 Blade に波及)
  • routes/web.php のリソース化・分割
  • CSVHelper 抽出(6重複、段階移行可)

F2-8.観点: フロントエンド構造

定量サマリー、外部JS総量: 709行、Blade直書きJS: 概算9,000行超で極端にBlade偏在

  • 【高】diagram-editor のグローバル名前空間の脆弱性
  • 【高】schedules の Alpine コンポーネントが Blade 直書き(setup.js との方針不一致)
  • 【中】ai_print_item / diagram_editor(旧版)のインラインハンドラ残存(移行漏れ)
  • 【中】★ x-submit-button 不徹底
  • 【低】help モーダル@push(‘styles) 未活用のインラインstyle
  • フロントエンド アーキテクチャ改善ロードマップ・・現状の最大リスクは「移行の中途半端さ」。edit_section だけ移行され、同一機能の standalone版・スケジュール・印刷エディタが旧方式のまま残るため CSP 強化(unsafe-inline 除去)に踏み切れず労力が死蔵している。画面単位ではなく機能(diagram-editor / schedules / TipTapエディタ)単位で移行を完結させることを推奨。
F2-9.単一ファイルで着手可能(★)一覧 — このチャットで直接修正する候補
提案対象ファイル
projects.company_id にインデックス追加新規マイグレーション1本
login_logs.company_id新規マイグレーション1本
空モデル ChecklistResult/SafetyJudgment の整理各モデル
config/anthropic.php 拡張config/anthropic.php
role 定数化(定義)app/Models/User.php
ProjectPlanController 親子チェックのヘルパー集約ProjectPlanController.php
README.md 実態反映README.md
CLAUDE.md 命名規約の明確化CLAUDE.md
スケルトンテスト削除tests/*/ExampleTest.php
テナント分離テスト拡充(工程表系)TenantIsolationTest.php
外部URLの config 化config/services.php ほか
F2-11.要確認事項
  1. StylePreset / AiFormatPreset の仕様: 全社共通設定として共有が正しいのか、テナント別にすべきか(company_id 追加の要否)。
  2. Docx/Xlsx 出力の正系統: 手書き系(generateDocxFromHtml)とサービス系(DocxRenderer)のどちらを残すか。MEMORY では「AI→JSON→DocxRenderer方式へ移行」とあるが未完。
  3. 空モデル ChecklistResult / SafetyJudgment: 使用予定があるか、削除してよいか。
  4. construction_plans/ai_print_item.blade.php の扱い: 旧版 construction_plans 廃止(TAM決定済み)に ai_print_item も含まれるか。新版 project_plans に AI印刷相当が移行済みかで判断が変わる。
  5. 命名規約: 「変数はスネークケース」を実態(camelCase許容)に合わせて緩和するか、逆に統一に向けて強制するか。
  6. BelongsToTenant 導入の実施時期: フェーズ1 Critical 群の応急修正(abort_if 2行)を先に入れ、恒久策は別フェーズで、という段取りでよいか。

ブックマーク パーマリンク.

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

  • 2026年7月
     12345
    6789101112
    13141516171819
    20212223242526
    2728293031