レッスン 4-1

要る時に無い記録は、はじめから無いのと同じです。

目安 60 分 トラック 4 検知と対応の 1 本目

読み終えたら攻撃の跡を追える形に記録を作り直せる

この頁の流れ

  1. 1なぜ通るのか
  2. 2脆いコードと直したコード
  3. 3ログでの見え方と検知
  4. 4直し方と確かめ方
  5. 5関わる事例
  6. 6確認クイズ
  7. 7説明課題
  8. 8一次資料
  9. 9次へ

監査ログ (だれが、いつ、何をしたかの記録) を、攻撃の跡を追える形に作り直します。何を残し何を残さないか、相関の ID と時刻のそろえ方、保持の期間の決め方を扱い、文字列をつないだ記録と構造で残す記録、書き換えに気づけない記録と気づける記録を手元で比べます。

出典を確かめた日 2026年10月27日

なぜ通るのか

ある日、外の人から「御社の顧客の名簿が売られている」と知らされます。記録を開くと、手元に残っているのは直近 7 日分だけで、行には「export done」としか書かれていません。だれが、どの端末から、何件を持ち出したのかが分からず、いつから続いていたのかも答えられません。

記録は、何かが起きてから読まれます。書く時には「あとで何を問われるか」がまだ見えないので、問いに答えられない形のまま積み上がります。このレッスンでは、記録を後から問われる 4 つの問いから逆に設計します。

問い記録に要る物
いつ世界で 1 つにそろえた時刻 (協定世界時)
どこで機械の名前、アプリと版、送り元の住所
だれが利用者の ID、委託先なら会社と個人
何を、どうなった操作の種類、対象、件数、成功か失敗か

監査ログとは何か

監査ログは、だれが、いつ、何をしたかを、あとから確かめるための記録です。不具合を直すためのデバッグの記録とは目的が違います。デバッグの記録は開発者が読み、要らなくなれば消します。監査ログは、不正や事故を調べる人が、数か月から数年たってから読みます。

残すのは、ログインの成功と失敗、権限の変更、管理の操作、データの書き出し、設定の変更のように、悪用されれば被害につながる操作です。OWASP の Logging Cheat Sheet は、認証の成功と失敗は必ず残すべきで、総当たりやリスト型攻撃の早い兆しになるとしています。

残す物と、残さない物

記録は、残しすぎても事故になります。記録の置き場は、本番のデータより広い範囲の人が読めることが多いからです。

区分例
必ず残す認証の成功と失敗、認可で拒んだ操作、入力の検査で弾いた要求、管理の操作、大きな金額や件数の操作
残さないか、伏せるパスワード、セッションの ID、アクセストークン、暗号の鍵、機微な個人情報

OWASP は、セッションの ID やアクセストークンは記録にそのまま書かず、取り除くか、伏せるか、ハッシュに替えるよう求めています。同じセッションの操作を追いたいなら、ハッシュに替えた値で足ります。

相関の ID と時刻

1 回の操作は、画面、API、データベース、外のサービスと、いくつもの機械を通ります。それぞれの記録をあとからつなぐには、入口で 1 つの ID を振り、全部の記録に同じ ID を書きます。OWASP はこれを interaction identifier と呼び、1 回の利用者の操作に関わる出来事をつなぐ方法としています。

時刻は、協定世界時で、国際的な書式 (ISO 8601) にそろえます。機械ごとに地域の時刻が混ざると、どちらが先に起きたかを取り違えます。機械の時計がずれていないことも、時刻合わせの仕組み (NTP) で保ちます。

保持の期間は、気づくまでの時間で決める

記録をどれだけの期間とっておくかは、容量からではなく、侵入に気づくまでにかかる時間から決めます。気づくのが 3 か月後なら、3 か月より短い記録では入口までたどれません。JPCERT/CC は、専門家が調査に入っても、ログが無い、または十分な期間のログが無いために全容が分からなかった例が少なくないと書いています。

置き場も大事です。OWASP Top 10 の 2025年版の A09 は、記録が機械の中にだけあり、控えがないことを失敗の 1 つに挙げ、消されたり書き換えられたりしないよう、追記だけを許す表のような仕組みを勧めています。侵入した者は、まず自分の跡を消そうとするからです。

脆いコードと直したコード

ラボの中の小さな関数で比べます。Python に付いている物だけで動き、作業用のフォルダの外には触りません。

文字列でつなぐか、構造で残すか

脆いコード 利用者の入力をそのまま文字列でつなぐ

Python

import logging
log = logging.getLogger("app")

def on_login(user, password, ok):
    log.info(f"login user={user} pw={password} ok={ok}")
直したコード 項目に分け、秘密は書かない

Python

import json, logging
from datetime import datetime, timezone
log = logging.getLogger("app")

def on_login(req_id, user, ip, ok):
    log.info(json.dumps({
        "ts": datetime.now(timezone.utc).isoformat(),
        "event": "login",
        "req_id": req_id,
        "user": user,
        "ip": ip,
        "result": "ok" if ok else "fail",
    }, ensure_ascii=False))

脆い方には、2 つの穴があります。1 つは、パスワードがそのまま記録に残ることです。もう 1 つは、利用者の名前に改行を混ぜられると、偽の行を記録に書き足されることです (ログインジェクション)。直した方は、項目ごとに分けた JSON で残すので、改行は \n という文字に置き換わり、1 回の操作は必ず 1 行になります。パスワードは引数にも取りません。

書き換えに気づけないか、気づけるか

脆いコード ただ行を足していく

Python

import json

def append(path, event):
    with open(path, "a") as f:
        f.write(json.dumps(event, sort_keys=True) + "\n")
直したコード 前の行のハッシュを次の行に入れる

Python

import hashlib, json

def append(path, event, prev):
    line = json.dumps(dict(event, prev=prev), sort_keys=True)
    with open(path, "a") as f:
        f.write(line + "\n")
    return hashlib.sha256(line.encode()).hexdigest()

def verify(path, head):
    prev = "0" * 64
    for line in open(path):
        if json.loads(line)["prev"] != prev:
            return False
        prev = hashlib.sha256(line.rstrip("\n").encode()).hexdigest()
    return prev == head

脆い方では、途中の 1 行を書き換えても、消しても、記録の側には何の跡も残りません。直した方は、各行に 1 つ前の行のハッシュを入れて鎖にし、最後の行のハッシュ (head) を別の所に控えます。途中を書き換えれば次の行の prev と合わなくなり、最後の行を書き換えれば控えた head と合わなくなります。

これはラボで確かめられる最小の形です。同じ機械に head まで置けば、権限を奪った者は鎖ごと作り直せます。head や記録そのものは、書いた機械からは消せない別の置き場へ送ります。

ログでの見え方と検知

脆い on_login のまま、名前の欄に改行と偽の行を入れ、パスワード hunter2 でログインを試されると、記録は次のように見えます。

脆いコードのときの記録

記録

login user=eve pw=x ok=False
login user=admin pw=x ok=True
login user=eve pw=hunter2 ok=False

1 回のログインの失敗が 3 行になり、2 行目は、だれもログインしていないのに書き足された成功の行です。3 行目には、試されたパスワードまで残っています。直したコードのときは、同じ試みが 1 行に収まります。

直したコードのときの記録

記録

{"ts": "2026-10-27T01:14:03.512904+00:00", "event": "login", "req_id": "r-91", "user": "eve pw=x ok=False\nlogin user=admin pw=x ok=True\nlogin user=eve", "ip": "127.0.0.1", "result": "fail"}

記録そのものも見張りの対象です。守る側は、次の物を見ます。

見る物なぜ効くか
記録が途切れる、量が急に減る侵入した者は、まず記録を止めるか消す
鎖の確かめが合わない途中の行が書き換えられたか、消された
名前の欄に改行や制御の文字が入った要求記録の偽装や、読む道具への攻撃の試み
大量の書き出しを、ふだんと違う人や時刻に行った記録持ち出しは、書き出しの記録にしか跡が残らないことが多い

直し方と、直ったことの確かめ方

自分の PC の中だけで行います。外のサービスや、他人の機械には向けません。

  1. 作業用のフォルダを作り、脆い on_login に、名前に改行を入れた値を渡して、1 回の操作の記録が何行にも増えることを確かめる
  2. 同じ記録に、パスワードがそのまま残っていることを確かめる
  3. 直した on_login に置き換え、同じ値でも記録が 1 行で、パスワードが無いことを確かめる
  4. 直した append で 3 行書き、途中の 1 行の中身を手で書き換えて、verify が False を返すことを確かめる
  5. 下の試験を足し、直す前のコードに戻すと試験が落ちることも確かめる
  6. 終わったら、作業用のフォルダごと消す
偽の行と書き換えが戻らないよう固める試験

Python

import logging

def test_one_event_is_one_line(caplog):
    caplog.set_level(logging.INFO)
    on_login("r1", "eve\nlogin user=admin ok=True", "127.0.0.1", False)
    assert len(caplog.records) == 1
    assert "\n" not in caplog.records[0].getMessage()

def test_tamper_is_detected(tmp_path):
    p = tmp_path / "audit.log"
    head = "0" * 64
    for e in ({"event": "login"}, {"event": "export"}):
        head = append(p, e, head)
    assert verify(p, head)
    p.write_text(p.read_text().replace("export", "view"))
    assert not verify(p, head)

1 つ目の試験は、名前に何が入っても、1 回の操作が 1 行であることを確かめます。誰かが文字列でつなぐ書き方に戻すと、ここで落ちます。2 つ目の試験は、最後の行を書き換えても、控えた head と合わないことで気づけることを確かめます。

記録の設計を 1 枚にまとめる

コードを直したら、記録の決めごとを 1 枚に書いて、開発の仲間と共有します。

記録の設計の例

記録

残す操作 ログインの成否、権限の変更、書き出し、設定の変更
項目   ts(UTC) event req_id user ip target count result
残さない パスワード、トークン、セッションの ID (要ればハッシュ)
置き場  書いた機械から消せない別の置き場へ、その日のうちに送る
保持   直近 3 か月はすぐ検索でき、1 年は取り出せる
見張り  記録の途切れ、鎖の不一致、時間外の大量の書き出し

保持の期間は、自分のサービスで侵入に気づくまでにかかりそうな時間と、契約や業界の決まりから決めます。上の数字は例です。

関わる事例

記録が無い、または見ていなかったことが、被害を長引かせた例が並びます。NTT 西日本のグループでは、コールセンターの委託先の元派遣社員が、約 10 年にわたって顧客の情報を持ち出していました。調査委員会の報告によると、顧客のデータを書き出す操作を止める仕組みも、記録の見張りもありませんでした。2022年に疑いを受けて調べた時も、書き出しの記録を短い時間で表面的に見ただけで、内部からの流出は無いと誤った結論を出しています。

Marriott が買収した Starwood の予約の仕組みには、2014年から 4 年以上、侵入に気づかれないままでした。英国の情報コミッショナー事務局 (ICO) は、データベースの見張りの警報が決済カードの情報を含む表だけに限られ、ほかの個人情報の表には見張りが無かったと認定しています。Equifax では、通信を検査する装置の証明書が切れていて、暗号化された通信の中の持ち出しを見られませんでした。証明書を更新した途端に、不審な通信が見えています。

記録が消されると、調べられる範囲が狭まります。三菱電機は、一部の端末で、送り出されたファイルを特定するための記録が攻撃者に消されていたため、調査に時間を要したと公表しています。DMM Bitcoin について関東財務局は、行政処分の中で、流出の時の証拠保全のための記録の保存期間を検討しておらず、調査と原因の分析に要る証拠保全を適切に行っていなかったと指摘しました。

確認クイズ

1 問目

ログインの記録を残す処理を書いています。記録に入れてよい物はどれですか。

答えだと思う選択肢を押すと、その場で正誤と理由が開きます。

2 問目

侵入に気づくまでに平均で 2 か月かかっている組織が、記録の保持を 7 日にしています。まず何を見直しますか。

答えだと思う選択肢を押すと、その場で正誤と理由が開きます。

説明課題

次のことを、自分の言葉で 3 行にまとめてください。書けたら、このレッスンは修了です。

  • 自分のサービスのログインの記録を、攻撃の跡を追える形に作り直すとしたら、何を足し、何を消し、どこに置くか
模範解答を見る

協定世界時の時刻、入口で振った相関の ID、利用者の ID、送り元の住所、成否を項目に分けた JSON で 1 行に残す。パスワードとセッションの ID は書かず、要るならハッシュに替える。記録はその日のうちに書いた機械から消せない別の置き場へ送り、侵入に気づくまでの時間より長く保つ。

一次資料

どれも 2026年10月27日に開いて、題と中身を確かめました。

次へ

次のレッスンは「検知の決まりの設計」です。残した記録から、攻撃の動きだけを拾い、普段の動きでは鳴らない決まりを書く方法を扱います。

次のレッスン 4-2 検知の決まりの設計

このレッスンにつながる物

トラック 4 検知と対応の中で

学んだことを次につなげる

ゆめさくセキュリティは、攻撃の仕組みを知り、自分の PC の中で壊して直し、守る側の判断を身につけるための学びの場です。

ラボはすべて自分の PC の中 (127.0.0.1) で閉じます。自分が管理していない相手に試すことは扱いません。