今日は雨の日曜日・・・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.実行手順
- リポジトリ構成を把握する(app/, routes/, resources/views/, resources/js/, database/, config/, public/ を中心に全体を読む。vendor/, node_modules/ は除外)
- フェーズ1を実行し、レポートを出力して停止・確認を待つ
- 承認後フェーズ2を実行し、レポートを出力して停止
- 承認後フェーズ3を実行し、レポートを出力して完了報告
- 各フェーズの完了報告には「検証したファイル数」「読み飛ばした箇所とその理由」を必ず含める(検証の網羅性を判断できるようにするため)
F1.セキュリティ検証レポート(フェーズ1)
F1-1.検証規模
- コントローラ: 約40ファイル / モデル: 約50ファイル / Blade: 約168ファイル / ルート: 3ファイル / サービス: 8ファイル
- 検証観点: A テナント分離 / B 認証・認可 / C 入力検証・インジェクション / D XSS / E CSP / F CSRF・セッション / G ファイルアップロード / H 情報漏洩 / I 依存パッケージ
F1-2.指摘件数(重大度別)
| 数 | 主な内容 | |
|---|---|---|
| Critical | 7 | クロステナント IDOR 群(工程表・安全パトロール・RA・施工計画書)、CSP unsafe-inline + 保存型XSS の複合、phpspreadsheet SSRF/RCE |
| High | 12 | テンプレート認可欠落、機密ファイルの public 保存、保存型XSS(図面/AI-HTML/style属性)、依存パッケージ High、-tmp/_old ファイルのオートロード混入 |
| Medium | 15 | Mass 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(実測)
| 数 | ファイル |
|---|---|
| 1548 | ConstructionPlanController.php |
| 952 | ProjectPlanController.php |
| 865 | NetworkScheduleController.php |
| 687 | SafetyPatrolController.php |
| 573 | EnvironmentController.php |
| 432 | RiskAssessmentController.php |
| 392 | BarChartController.php |
| 350 | ChecklistController.php |
| 313 | UserController.php |
| 251 | CompanyAdminController.php |
【高】Blade巨大ファイル(インラインJS肥大)
| 数 | ファイル | 特記 |
|---|---|---|
| 3082 | schedules/network.blade.php | 単一<script> が724-3080の約2356行 |
| 2439 | schedules/barchart.blade.php | 同様の巨大インラインJS |
| 1875 | projects_plan/edit_section.blade.php | @push(‘scripts’)+diagram-editor-script include+openCtxMenu上書きIIFE |
| 854 | environment/edit_environment.blade.php | |
| 729 | projects_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分割済み(良い設計)だが個別ファイルが肥大:
| 数 | ファイル | 責務 |
|---|---|---|
| 1541 | diagram-editor-nodes.blade.php | ノードCRUD/RTB/画像/線ノード |
| 1132 | diagram-editor-table.blade.php | 表/Excel貼付/xspreadsheet |
| 726 | diagram-editor-ui.blade.php | 右クリック/保存/ページ/テンプレ/印刷 |
| 602 | diagram-editor-connect.blade.php | コネクタ/接続線ダイアログ |
| 154 | diagram-editor-core.blade.php | 状態/Undo-Redo/グリッド |

