監査ログ

監査ログとは

監査ログ(audit log)は、システムに対する操作の証跡を残す記録です。「管理者Aが 9月23日 10:12 に検索語『xxx』のステータスを open から done に変えた」のように、誰が・いつ・何を・どのように変えたかを1行ずつ積み上げます。

目的はデバッグではなく説明責任です。障害や不正が疑われたとき、「その時点で誰に何ができたか」「実際に何が行われたか」を第三者にも示せる状態にしておくことが監査ログの仕事です。[[ログ設計]] で扱う一般的なアプリケーションログと目的が違うため、設計も別に考えます。

アプリログとの違い

観点アプリケーションログ監査ログ
主な読者開発者・運用者管理者・監査担当・(必要なら)法務
記録する単位処理の進行・エラー権限を持つ主体による操作
欠落の扱い多少抜けても困らない抜けてはいけない(操作と同じトランザクションで書く)
保持期間数日〜数週間数か月〜数年(規制や社内規程で決まる)
変更ローテーションで消える追記のみ。更新・削除を許さない

「操作と同じトランザクションで書く」が実装上の要点です。操作は成功したのに監査ログだけ失敗した、という状態を許すと証跡に穴が空きます。データベース側で本体の更新と監査行の挿入を1つのトランザクションにまとめるか、[[Row Level Security(RLS)]] と組み合わせて「監査行を書ける関数経由でしか本体を更新できない」構造にします。

何を記録するか

最低限そろえる項目は次の5つです。

  • 主体(actor) — 操作したユーザーの識別子。表示名ではなく変わらない ID を使う
  • 対象(target) — 操作されたレコードの種類と ID
  • 動作(action) — update_status のような決まった語彙。自由文にしない
  • 時刻 — サーバー側の時計で記録する。クライアントの時刻は信用しない
  • 前後の値 — 何から何へ変わったか。「変えた」だけでは復元も検証もできない

これに加えて、ログインの成功・失敗も監査の対象です。失敗の連続は総当たりの兆候であり、成功の直後に権限が使われた記録と突き合わせると侵害の時系列が組み立てられます。[[認証と認可]] の記録を別テーブルにするか同じテーブルに入れるかは設計次第ですが、同じ「追記のみ」の性質を持たせます。

出してはいけないもの

監査ログは長く残り、閲覧できる人も増えます。そのため書く内容の選別は通常のログより厳しくします。

  • パスワード・トークン・APIキーは絶対に書かない([[シークレット管理]])
  • 利用者の自由入力を生のまま複製しない。検索語やメモ欄には個人情報が混じりうる。前後の値には「変わった」という事実と識別子を残し、本文そのものは元テーブルへの参照で足りるようにする
  • 前後の値を JSON で丸ごと入れる実装は便利だが、元テーブルの列が増えたときに秘密情報まで自動で流れ込む。列を明示して詰める

「識別子は伏せない」という判断も重要です。伏せすぎると「誰がどのレコードを操作したか」が追えなくなり、監査ログが用を成しません。生値の複製を減らし、保持期間で総量に上限を付けるのが落としどころです。

記録の仕組み自体を守る

監査ログは攻撃者にとっても標的です。侵入の痕跡を消したい者はまずログを狙います。

  • 追記のみの権限 — アプリケーションの接続ユーザーには INSERT だけを許し、UPDATE / DELETE は与えない([[最小権限の原則]])
  • 書き込み経路の回数制限 — ログイン失敗を記録する関数が無制限に呼べると、大量の偽イベントで本物を埋める攻撃に使える。記録する関数自体にレート制限をかける
  • 保持期間の明示 — 「永久」は現実には運用できない。400日など根拠のある期間を決め、期限切れの削除だけは定期ジョブに許す
  • 別の場所への複製 — 本体と同じデータベースにしか無いと、データベースごと消されたときに証跡も消える。重要なものは外部ストレージへ転送する

初学者向けポイント

  • 「あとで見返せる」ことがすべてです。書き忘れた操作は後から再現できません。権限を持つ操作を1つ増やしたら、監査行を書く処理をセットで足す習慣を付けましょう
  • 動作の語彙を決めるときは、将来「この操作は何回行われたか」を数えられる粒度にします。update 1種類では役に立ちません
  • 監査ログを見る画面も権限の対象です。誰でも読めると、それ自体が情報漏えいの経路になります

関連技術とのつながり

  • [[ログ設計]] — アプリログとの役割分担。出してはいけない情報の原則は共通
  • [[インシデント対応]] — 障害・侵害の時系列を組み立てる主資料
  • [[最小権限の原則]] — 追記のみの権限設計はこの原則の適用
  • [[認証と認可]] — ログイン成功・失敗の記録は監査の入口
  • [[シークレット管理]] — 秘密情報をログへ流さないための前提
  • [[Row Level Security(RLS)]] — 本体の更新と監査行の挿入を同じ経路に閉じ込める手段
Q: 監査ログとアプリケーションログの最も大きな違いはどれ?
- [ ] 監査ログは JSON 形式でなければならない
- [x] 監査ログは欠落を許さず、追記のみで更新・削除を認めない
- [ ] 監査ログは開発者だけが読む
解説: 監査ログは説明責任のための証跡なので、操作と同じトランザクションで書き、後から書き換えられない性質を持たせます。

Q: 監査ログの「前後の値」に利用者の自由入力を生のまま複製しない理由はどれ?
- [ ] 文字数が多いと検索が遅くなるから
- [x] 個人情報が混じりうる値の複製が増え、長期間・広い範囲に残ってしまうから
- [ ] 前後の値は監査に不要だから
解説: 変わった事実と識別子は残しつつ、本文の複製を減らして保持期間で上限を付けるのが落としどころです。

Q: 監査ログを書く関数にレート制限をかける目的はどれ?
- [x] 大量の偽イベントで本物の記録を埋める攻撃を防ぐ
- [ ] データベースの容量を節約する
- [ ] ログの時刻を正確にする
解説: ログイン失敗の記録などが無制限に呼べると、ノイズで証跡を埋められます。記録の仕組み自体も守る対象です。