TT Lab
はじめる
学ぶ 学習パス コース

銀行現場の言葉

限度額は上がっているのに、上げた人がいない

TT Labで続きを見る

一言でいうと

監査証跡は、値を保存することではなく、あとで争える形で残すことです。その場でのUPDATEの代わりに追記のみの記録を置き、正規化シリアライズで同じイベントが常に同じバイトになるようにしたうえで、ハッシュチェーンと鍵で「途中で手を加えれば表に出る」性質を付けます。

なぜ必要なのか

銀行で監査対応が難しくなる瞬間は、たいてい値が間違っているときではありません。値は合っているのに、その値がどうやってそこまで来たのか、誰も説明できないときです。与信限度額のテーブルが、UPDATE customer_limit SET limit_amount = ? WHERE customer_id = ?の1行で更新されるシステムを考えてみましょう。この文が回った瞬間、古い値は消えます。残るのはupdated_atとupdated_byの列だけですが、それも最後の1回の痕跡なので、その前に何回経てきたのかはわかりません。

現場では、この問題は次のように現れます。月末の点検で、限度額の合計が月初より4億8000万ウォン増えています。変更申請書を数えてみると、件数が合いません。何件かは申請書がそもそもなく、何件かは申請書に書かれた承認金額と今の値が違います。このとき担当者に尋ねると、たいてい正直な答えが返ってきます。「バッチで一括反映しました」。そのバッチが何をしたかは、どこにも残っていません。監査で最も高くつくのは、間違った数字ではなく、説明できない数字です。

米国NISTのSP 800-92ログ管理ガイドがログを扱うなかで繰り返し述べていることも、同じです(全文PDF)。ログは生成して終わりではなく、保管・保護・検証までを1つのまとまりとして設計する必要があり、完全性が守られていないログは、証拠としての価値が大きく下がります。韓国の金融機関の実務における具体的な保存年限は、機関ごとに異なるので、このラボでは扱わず、記録をどう作ればあとで証明できるかにだけ集中します。

どう動くのか

第一に、追記のみのテーブルを置きます。状態を上書きするテーブル(現在の限度額)と、イベントを積み上げるテーブル(監査記録)を、別々に置きます。現在の値は高速な照会のための派生物で、真実はイベントの並びです。

第二に、イベントを同じバイトにします。ハッシュはバイトに対して計算されるので、{"a":1,"b":2}と{"b":2,"a":1}は同じイベントなのに、異なるハッシュになります。RFC 8785 JSON Canonicalization Schemeが、この問題を規格として確定しました。オブジェクトのキーを並べ替え、区切り文字の周りの空白をなくし、UTF-8でシリアライズします。Pythonでは、jsonモジュールのsort_keys=True、separators=(",", ":")、ensure_ascii=Falseの3つを有効にすれば、ほとんどの実務のpayloadで同じ結果が出ます。ただし、RFC 8785はキーの並べ替えをUTF-16コード単位を基準に定義し、Pythonはコードポイントで並べ替えるので、絵文字のような補助面の文字をキーに使うとずれます。実務では、キーをASCIIに限定するほうが安全です。

第三に、チェーンでつなぎます。項目ごとに、前の項目のハッシュをprev_hashとして抱え、自分の内容とprev_hashを一緒にハッシュしてentry_hashを作ります(hashlib)。途中の1行を直すと、その行のentry_hashがずれ、その行のハッシュを再計算して差し込めば、後ろの項目のprev_hashがずれます。チェーンは「直せなく」はしません。直せば表に出るようにします。

第四に、チェーンの上に鍵を載せます。ハッシュチェーンだけだと、記録全体にアクセスできる人が、最初から最後まで再計算して、まるごと差し替えられます。hmacモジュールで項目ごとにMACを作り、その鍵を記録とは別の場所に置けば、鍵を知らない人は再計算できません。鍵が同じDBの中にあれば、この性質はまるごと消えます。

app_log(원본)  ──▶ canon(사건) ──▶ sha256 ──▶ entry_hash  ──┐
                                   ▲                        │ prev_hash 로 다음 항목에
                                   └──────── prev_hash ◀────┘
                    entry_hash + prev_mac ──▶ HMAC(열쇠) ──▶ entry_mac

このコードブロックの韓国語コメントは、app_logが元のデータであること、canonの引数がイベントであること、prev_hashによって次の項目につながること、MACの鍵がHMACの鍵であることを述べています。

現場での姿

最もよくある失敗は、相関IDのないログです。1回の限度額変更が、窓口アプリ、限度額サービス、コアバッチ、監査リレーを順に通り抜けるのに、各システムが自分のイベントだけを残します。あとから「この変更はどこで始まったのか」と問われると、時刻が近い行を目で貼り合わせるしかありません。リクエスト1つにIDを付けて全区間に流せば、調査時間が時間単位から分単位に縮まります。逆に、途中で1つのシステムがそのIDを落とすと、その地点以降は再び推測になります。

2つ目は、協力会社から受け取った持ち出し版をそのまま信じることです。チェーンが付いているからといって、検証したという意味ではありません。受け取ったファイルを最初から再計算してみると、内容だけを直して入れた箇所、項目がまるごと抜けた箇所が表に出ます。2つは症状が違います。内容を直せばその行のハッシュがずれ、項目を抜けばその次の行のつながりがずれます。

実務で本当に大切なこと

次のラボですること

ハンドゥル銀行(架空)の限度額スナップショットを自分で作り、申請書なしで変わった件と、承認値と異なって反映された件を、数字で浮かび上がらせます。そのあと、正規化シリアライズのツールを作り、採点ツールが毎回異なる並びで渡すベクターに合わせ、ログ400行をハッシュチェーンで束ねます。協力会社の持ち出し版で手が加えられた箇所を見つけ出し、HMACで再計算による偽造を防ぎ、相関IDでイベントをリクエスト単位に束ね直したうえで、ハッシュ付きの証跡バンドルを出します。