セキュリティベースライン
概要
完全なリファレンスは references/baseline.md にあります(セクション§0〜§18、## N. でgrep)。このファイルが運用手順です。基本原則:厳格さを脅威階層に一致させ、各発見をエビデンスで証明する。 三つの法則:クライアントを信頼するな、モデルのコードを信頼するな、デフォルトを信頼するな。
モードを選択
| リクエスト | モード | baseline.md で読む箇所 |
|---|---|---|
| 「安全にプロジェクトを計画・開始する」、エージェントルールを書く | 計画 | §0, §2, §3, §16 |
| 「このアプリ/リポジトリ/PRをレビュー/監査する」 | コードレビュー | §1.3, §4–§11, §15.2 |
| 「自分のサーバー/ホームラボ/VPSを監査する」、「最新か確認する」 | ホスト監査 | §3.3, §8.3, §12, §13 |
| 「ハッキングされた/鍵が漏洩した」 | インシデント | §17, §8.2 |
ホスト監査には、アカウントや個人データを保持する各インターネット公開アプリに対する短いコードレビューが含まれます。
ステップ1 — 階層を分類する(常に最初に行い、レポートに明記する)
観察可能な事実から判断し、所有者の呼び方から判断しない:
| 階層 | 条件 | 適用するセクション |
|---|---|---|
| T0 おもちゃ | 実ユーザーもデータも無い、かつインターネットから到達不可能(LANのみ、またはSSOの内側) | §2, §8 |
| T1 公開、アカウント無し | インターネット到達可能、ログイン無し、個人データ保存無し | T0 + §9, §10 |
| T2 アカウント/ユーザーデータ | 何らかのログイン、何らかの個人データ(名前、メール、ゲストリスト)、保持するAPIキーやトークン | 全て |
| T3 金銭/PII規模/規制対象 | 決済、健康、認証情報保管庫、金融、1,000人以上のデータ、顧客契約 | T2 + 外部レビュー + §14 |
ホームラボホストは、それが実行するものの中で最も高い階層で評価される。認証情報アグリゲーター(パスワードマネージャー、n8n、Home Assistant、Portainer、docker.sock保持者)は、ブラスト半径によりT3とする。
ステップ2 — エビデンスを収集する(読み取り専用)
バンドルされたスクリプトをbashで実行する。リモートホストの場合は、SSH経由でストリーミング:ssh host 'bash -s -- --remote-digests' < scripts/audit-docker-host.sh および ssh host 'bash -s -- <project-dir>' < scripts/scan-code.sh。
bash scripts/audit-docker-host.sh --remote-digests— OSパッチ、再起動フラグ、リスニングソケット、ファイアウォール、sshd、各コンテナのユーザー/権限/公開ポート/docker.sock、秘密らしい環境変数名、イメージの鮮度(UP-TO-DATE / OUTDATED / local-build)。bash scripts/scan-code.sh <project-dir>— シークレット、インジェクション、XSS、マスアサインメント、クライアント提供のテナントID、フェイルオープンキャッチ、弱い暗号、ロックファイル、Dockerfile/composeリスク、ルートインベントリをgrep。
その後、スクリプトではできないことを行う:
- リバースプロキシインベントリ:すべての公開ホスト名、そのターゲット、および認証が前面にあるかどうかをリストアップする(NPM DB / Caddy / Traefikラベル)。SSOやアクセスリストなしで公開ホスト名にある管理UI(§3.3リスト) = 発見。
- 外部ビュー:LANの外部パスから、
curl -sI https://<host>でヘッダーを確認(§10.2)、/.env、/.git/config、/admin、/apiをGETのみでプローブ。 - 認可トレース:各T2+アプリについて、ルートごとに認可チェックの名前とプリンシパル/テナントIDの取得元を特定する(§4.3)。§1.3の質問を適用する。
- プロキシの信頼:アプリが
X-Forwarded-Forを読み取る場合、どのホップを信頼するかを確認する($proxy_add_x_forwarded_forは追記する;最初の値は攻撃者によって制御される)。 - ロールごとの認証情報強度:すべてのロール(管理者、スタッフ、ボランティア、API/MCPトークン)について、その秘密がどのように設定されているか、シード、レガシーおよび通常の長さチェックをスキップする移行パスを含めて確認する。
.env値の実際の長さはawk -F= '{print $1, length($2)}'で確認し、決して印刷しない。弱い秘密とバイパス可能なレート制限は、2つの発見としてではなく1つの発見として扱う。 - バージョン vs アドバイザリ:インターネット公開アプリごとに、実行中のバージョンを現在のリリースおよび既知のCVEと比較する。製品のセキュリティアドバイザリについてはWeb検索を使用する。
ホストゲート(§16のチェックリストはプロジェクトごと;ホストにはこれを使用)
- すべての公開ホスト名がリストアップされ、各管理UI(§3.3)にはSSO、アクセスリスト、VPNのいずれかが前面にあり、公開されていない
- ハイパーバイザー、Docker、NPM/プロキシ管理、パスワードボールト管理:決して公開しない
- 必要のないすべてのセルフホストアプリ(Vaultwarden、Open WebUI、Gitea、Immichなど)で、オープンサインアップが無効になっている
- WAN到達可能ポート = 80/443のみ(+ VPN)。Docker公開ポートはufwをバイパスする:ルーターフォワードと
DOCKER-USERを確認 - プロキシが、アプリが騙されないクライアントIPを渡している(§4.5、X-Forwarded-For)
- dockerグループのメンバーがリストアップされている;各メンバーはrootと同等
- シークレットファイルのモードは600;ワールドリーダブルな
.env/鍵は無し - OSパッチ済み、7日以上経過した保留中の再起動無し;イメージは最新(鮮度テーブル)
- バックアップが最近実行され、リストアがテストされている(§13.4)
行動規範
- デフォルトで読み取り専用。書き込み、再起動、更新、データを変更するPOST、ブルートフォース、所有者が所有していないホストのスキャンは禁止。
- 秘密の値を決して印刷しない。変数名とファイル:行のみを報告する。
- 設定ストア(DB設定テーブル、JSON設定、
docker inspect環境)は キーと長さのみ で検査する:jq 'paths'、SELECT key FROM …、awk -F= '{print $1, length($2)}'。確認のために設定行やファイル全体をダンプしない:APIキーが含まれている可能性がある。 - 変更(更新、chmod、設定修正)は、レポート作成後、かつリクエスト者が変更を依頼した場合のみ行う。更新については以下の「安全に更新する」に従う。
ステップ3 — レポート(この正確な形式)
- スコープと階層:何を調査したか、階層、および一言の理由。
- 評決:一文 — 出荷可 / 修正優先 / 停止。
- 発見事項、Critical→Low の順にランク付け。各発見には:タイトル、
CONFIRMED(再現した、または正確なコード/設定パスを読んだ)あるいはLEAD(もっともらしいが証明されていない)、エビデンス(ファイル:行、コマンド+出力抜粋)、影響(一文)、修正方法。 - 鮮度テーブル(ホスト監査):コンポーネント、実行中バージョン、最新バージョン、更新のリスク。
- カバレッジ:確認した§16ゲートセクション、確認しなかったセクションとその理由。沈黙は合格ではない。
- 次のアクション、番号付き、最小労力・最大リスク順。
安全に更新する(「すべてを最新にする」)
- バックアップが存在し、最近のものであることを確認する(§13.4)。各コンテナの現在のイメージIDを記録し、ロールバックを
image: <repo>@<old digest>で行えるようにする。 - ステートレス = アプリが書き込む名前付きボリュームやバインドマウントが無く、データベースも無い。静的nginxサイト、gotenberg、flaresolverrはステートレス。不明な場合は、データ保持として扱う。
- 分類する:データ保持またはスキーママイグレーション(データベース、Immich、Paperless、Vaultwarden、Firefly、n8n、Home Assistant)→ 一度に一つ、最初にリリースノートで破壊的変更を読む。ステートレス(nginx静的サイト、ツール)→ まとめて行う。
docker pullでデータベースのメジャーバージョンを飛ばさない(postgres 15→17)。ダンプ/リストアが必要。- プロジェクトごとに
docker compose pull && docker compose up -dを実行し、ヘルスチェックを行う:コンテナステータス、エラーのログ、公開URLのHTTPチェック。 - ローカルビルド(
local-build)は--pullでリビルドして更新する。OSパッケージにはsudoが必要;持っていない場合は、リストと再起動フラグを報告する。 - プルが
429 toomanyrequestsで失敗したら停止する。ホストでdocker loginを依頼するか、6時間後に再試行する。ループしない。
よくある間違い
| 間違い | 正しい方法 |
|---|---|
| すべてを「高」として報告する | 深刻度 = 悪用可能性 × 階層 × ブラスト半径 |
| スクリプトのヒットを発見として扱う | コードを読むまではスクリプト出力はLEAD |
| 確認せずに「コンテナがrootとして実行されている」と言う | 多くのイメージはエントリポイントで権限を落とす;内部で ps を確認する |
| LANホストで「ポート9000が開いている」と言う | 誰が到達できるかを言う:LANのみ、WAN(ルーターフォワード経由)、またはプロキシ経由 |
| 階層をスキップして、静的なサイトを銀行のように監査する | 階層を先に;T1はヘッダーと依存関係が必要であり、RLSは不要 |
:latest で一度にすべてを更新する | データ保持サービスは一度に一つ、ロールバック用のダイジェストを添えて |
コントロールを無効にして修正する(RLSオフ、CORS *) | ポリシーを修正し、決して削除しない(§7.2) |