人が染み込んだログを外へ出せる形にする
目標
人と組織が紛れ込んだ運用ログから識別子を見分け、鍵に結びついた決定的な仮名化とマスキングを分けて適用し、残る再識別のリスクを一般化で減らしたうえで、持ち出しパッケージを機械で自己検証して出します。
なぜ重要なのか
エアギャップ環境で解けない障害が起きると、ログを外に送らなければならない瞬間が来ます。そのとき社員番号をアスタリスクで覆うと、審査は通りますが、分析が死にます。障害分析が使う事実は、たいてい値そのものではなく、値が同じだという関係だからです。そこで必要になるのが、同じ値をいつも同じ仮名に置き換えつつ、元に戻せないようにする関数で、その場所を鍵付きハッシュが担います。このラボで難しい部分は、仮名の関数ではなく、何が識別子なのかを数えることです。ラベルが付いたフィールドは簡単で、メッセージ本文に文章のように埋め込まれた値と、エンコードの裏に隠れた値が、持ち出し物を漏らします。
ステップ
python3で/root/deid/dataに6つのデータファイルを作ります。生成スクリプトをそのまま使ってください。- フィールドごとの分類と一意な値の数と処理方法を、
/root/deid/classify.csvに書きます。 - 正規表現がフィールドで見つけた値と見逃した値を、
/root/deid/scan.jsonに書きます。 - 鍵に結びついた仮名関数を作って、
/root/deid/vault/map.csvと/root/deid/vault/proof.jsonを残します。 - 仮名化とマスキングを分けて適用し、
/root/deid/out/access.deid.logと/root/deid/out/app.deid.logを作ります。 - 準識別子の組み合わせで唯一になる行を数えて
/root/deid/risk.jsonに、一般化した分析表を/root/deid/out/events.csvに残します。 - 持ち出し物を、元の識別子の一覧で突き合わせた結果を、
/root/deid/selfcheck.jsonに書きます。 /root/deid/releaseに、仮名のデータと方法書と完全性だけを入れた持ち出しパッケージを作ります。
参考
- 識別子のパターン、マスキングするフィールド、エンコードされたフィールド、kの基準値は、すべて
/root/deid/data/policy.jsonにあります。数字や正規表現をコードに埋め込まず、そのファイルから読んでください。 - 仮名の鍵は
/root/deid/data/key.hexにあります。このファイルはネットワークの中に残り、持ち出しパッケージには入りません。 - 仮名は、
HMAC-SHA256(열쇠, 종류 + "|" + 값)(プレースホルダーは鍵、種類、値です)の16進出力の先頭pseudo_len文字に、prefixを付けたものです。例:EMP-0123456789ab。 - 変換の順序が結果を変えます。自由記述フィールドを先にマスキングし、エンコードされたフィールドをデコードして仮名に置き換え、そのあと残った行全体で、パターンに引っかかるものを仮名に置き換えます。
- 基準日は
/root/deid/data/asof.txtにあります。dateで今日を使うと、同じデータから日ごとに違う答えが出ます。 - よくある間違い1: ラベルが付いたフィールドだけを走査することです。メッセージ本文とエンコードされた値は、それでは出てきません。
- よくある間違い2: マッピング表を持ち出しパッケージに一緒に入れてしまうことです。そのファイルが入ると、仮名化をしていないのと同じです。
- 標準文書: RFC 2104、FIPS 198-1、NIST SP 800-92、NIST IR 8053。このラボのフィールド分類とkの基準値は、標準の統制番号ではなく、データの中でだけ使う、このラボの仮定です。
非識別化の土台になるデータを作る
python3で/root/deid/dataにaccess.log・app.log・roster.csv・policy.json・key.hex・asof.txtの6つを作ります。乱数を使わない生成スクリプトをそのまま使ってください。
エアギャップ環境にはダウンロードできるサンプルがないので、まずデータを自分で作ります。乱数を使わないからこそ、誰が何回回しても同じデータが出て、互いの判定を突き合わせられます。採点ツールは、データを標準形に変えてフィンガープリントを突き合わせるので、データを手で直すと、後のステップがすべて止まります。
どのフィールドが何かを分ける
/root/deid/classify.csvに、先頭行field,category,distinct_values,actionを置き、policy.jsonのfieldsごとに1行ずつ書いてください。distinct_valuesは、そのフィールドがデータの中で持つ一意な値の数で、actionは、action_by_categoryがその分類に定めている処理です。
分類は組織が決めたものなので、policy.jsonにすでに書かれています。やることは、その分類に合った処理を付け、データを実際に数えて、一意な値の数を埋めることです。一意な値の数が少ない列は、1つでは人を指せませんが、他の列と合わせると指せます。それが準識別子です。
正規表現が見つけたものと見逃したものを一緒に数える
/root/deid/scan.jsonに、field_values(種類別のフィールドの一意な値の数)、message_only(msgの中にだけあって、どのフィールドにもない値)、encoded(payloadをbase64でデコードして出てきた値)、note_only(noteの中にだけある値)の4項目を書いてください。後ろの3項目は、ソートした一覧です。
ラベルが付いた場所は、종류=값(プレースホルダーは種類と値です)で探します。そのあとが、このステップの核心です。msgとnoteの中の二重引用符の間を別に走査し、payloadは先にデコードしてから走査してください。どんな正規表現も、エンコードされた値を、原文の状態では見つけられません。
鍵に結びついた決定的な仮名を作る
/root/deid/vault/map.csvに先頭行kind,value,pseudonymを置いて、データから見つけた識別子ごとに1行ずつ書き、/root/deid/vault/proof.jsonに、values・pseudonyms・collisions・stable・key_sensitive・alt_key_overlapの6項目を書いてください。
仮名はHMAC-SHA256で作ります。種類と値を縦棒でつないで入れれば、社員番号とアドレスがたまたま同じ文字列でも、仮名が分かれます。テストは3つです。同じ値を2回計算して同じか、異なる値が同じ仮名にならないか、policy.jsonの別の鍵で計算すると、仮名の集合が1つも重ならないか。この金庫は、ネットワークの中に残ります。
仮名化するものとマスキングするものを分けて適用する
/root/deid/out/access.deid.logと/root/deid/out/app.deid.logを作ってください。自由記述フィールドは、policy.jsonのmask_tokenでまるごと置き換え、エンコードされたフィールドは、デコードした値の仮名に置き換え、残りのパターンは、すべて仮名に置き換えます。行数と行の順序は、原本と同じでなければなりません。
順序が結果を変えます。マスキングを先にしないと、自由記述の中の値が仮名に置き換わって残り、消すべきものが消えないまま出ていきます。エンコードされたフィールドは、デコードして、どの種類かを判定したあと、その種類の仮名を付けてください。同じ人が原文で出てきた場所と、同じ仮名になる必要があります。
直接識別子をすべて変えても残るリスクを数える
/root/deid/risk.jsonに、rows・k・groups_before・unique_before・groups_after・unique_afterの6つの数を書き、/root/deid/out/events.csvに、先頭行pseudo_emp,dept,grade,hourを置いた一般化した分析表を、アクセスログの行の順序どおりに残してください。
準識別子の組み合わせは、policy.jsonのquasiに書かれています。部署と等級は名簿から、時刻はアクセスログから来ます。まず分単位の時刻でまとめて、同じ組み合わせの行がk個未満の行を数え、そのあと時刻を時単位に切り捨てて、もう一度数えてください。減った分が、一般化で買った安全であり、失った精度が、その代価です。
持ち出し物に原本が残っていないかを機械で突き合わせる
/root/deid/selfcheck.jsonに、files_checked・forbidden_values・hits・pseudonyms_foundの4つの数を書いてください。forbidden_valuesは、データにあった識別子の全体の数で、hitsは、そのうち持ち出し物で見つかった件数で、0でなければなりません。
禁止リストは、仮名の金庫よりも広いものです。マスキングしてなくした値には仮名がありませんが、持ち出し物に出てきてもいけないからです。自由記述の中の値までリストに入れてください。突き合わせの対象は、outディレクトリのファイルで、禁止リストとselfcheckの結果は、その外に置きます。リスト自体が最も危険なファイルです。
金庫は内側に残して、パッケージだけを出す
/root/deid/releaseに、access.deid.log・app.deid.log・events.csvの3ファイルと、/root/deid/release/method.md、/root/deid/release/SHA256SUMSを作ってください。方法書は、## 무엇을 바꿨나・## 가명은 어떻게 만들었나・## 무엇을 지웠나・## 남은 위험・## 무결성の5つの節で、マッピング表と鍵は、パッケージに入れません(見出しは順に、韓国語で「何を変えたか」「仮名はどう作ったか」「何を消したか」「残るリスク」「完全性」を意味する語です)。
受け取る側は、仮名だけを見ます。そのため、何がどのルールで変わったかの説明が一緒に行かなければ、そのデータは、読めないデータになります。完全性のハッシュは、ファイルを最後に直したあとで取ってください。そして、パッケージに何が入ったかを、一覧でもう一度見てください。金庫を一緒に入れる事故が、最もよくあります。