一覧SP-10-2 · DLP:機微情報の識別と制御

DLPの送信先制御と監査ログ

識別条件、読める範囲、宛先別の制御と監査記録を分けて評価します。

説明

同じ機微情報でも、社内共有と外部公開では許可条件が異なります。警告時の上書き承認、配送を止める条件、ログへ残す情報の範囲を合わせて設計します。

固定の配送待ちDBへ文書を送る処理を使い、許可、警告、理由付き上書き、遮断を試します。監査記録をマスクしつつ、内容の同一性を照合する値も確認します。

識別条件、読める範囲、宛先別の制御と監査記録を分けて評価します。

1宛先と処理の規則を読む

team、partner、publicの3宛先です。

from sp10 import * from sp02 import show宛先と処理の規則を読む db=connect() show(db,"SELECT * FROM policy ORDER BY destination")

teamはallow、partnerはwarn、publicはblockです。この試料では登録値を含む文書に適用します。

2社内向けの配送待ちを作る

同じ本文をteamへ渡します。

print(send社内向けの配送待ちを作る(db,'team',TEXT)) show(db,"SELECT id,destination FROM outbox ORDER BY id")

allowとなりoutboxへ1件入ります。これは配送待ちへの登録であり、受信先への配送完了とは別の段階です。

3警告だけでは配送待ちへ追加しない

partnerへ同じ文書を渡します。

print(send警告だけでは配送待ちへ追加しない(db,'partner',TEXT)) show(db,"SELECT COUNT(*) AS queued FROM outbox")

warnで件数は1のままです。警告を表示しただけで処理を通すのか、確認まで止めるのかは規則として明確にします。

4理由を必須にした上書きを試す

空の理由と、確認内容を添えた理由を比較します。

print(send(db,'partner',TEXT,override=True理由を必須にした上書きを試す)) print(send(db,'partner',TEXT,override=True,reason='approved sample transfer')) show(db,"SELECT id,destination FROM outbox ORDER BY id")

空の理由ではwarn、理由ありでallow_overrideとなり2件目が追加されます。実運用では承認者や共有契約などの条件も合わせて確認します。

5公開宛先の遮断を上書きできないことを確認する

publicへoverrideを指定してもblock条件を優先します。

print(send公開宛先の遮断を上書きできないことを確認する(db,'public',TEXT,override=True,reason='requested')) print(send(db,'unknown',TEXT)) show(db,"SELECT COUNT(*) AS queued FROM outbox")

どちらもblockで配送待ちは2件のままです。未登録宛先も既定で拒否しています。

6監査ログで値をマスクする

処理結果、理由、マスク済み本文を表示します。

show監査ログで値をマスクする(db,"SELECT destination,action,reason,masked FROM audit ORDER BY id")

独立したIDはEMP-****に置換されます。ただし境界条件で検査対象外だった埋込み文字列は残ります。検知用の範囲とログ秘匿用の範囲を同じにすると、このような漏れが起こり得ます。

7ログ用のマスク範囲を広げる

保存済みマスク欄の埋込みIDも消します。

for ident,masked in db.execute("SELECT id,masked FROM audit").fetchall(): db.execute("UPDATE audit SET masked=? WHERE id=?",(re.subログ用のマスク範囲を広げる(r'EMP-[0-9]{4}','EMP-****',masked),ident)) show(db,"SELECT DISTINCT masked FROM audit")

XEMP-****Zとなり、生の4桁も残らなくなります。ログの秘匿は検知の判定と別に点検します。

8本文を表示せず同じ内容の試行を結ぶ

公開試験鍵のHMACで一致を照合します。

show(db,"SELECT COUNT(*) AS attempts,COUNT(DISTINCT digest) AS contents FROM audit") print(hmac.compare_digest本文を表示せず同じ内容の試行を結ぶ(hmac.new(PUBLIC_KEY,TEXT.encode(),hashlib.sha256).hexdigest(),db.execute("SELECT digest FROM audit LIMIT 1").fetchone()[0]))

6試行とも同じ値です。HMAC値を使って記録を関連付けられるため、この値もアクセス管理の対象にします。

まとめ

警告、上書き、遮断の適用条件を確認します。

配送待ちと配送完了を分けて追います。

ログのマスク範囲は検知条件とは別に点検します。

操作履歴と解説を振り返れます。

Python 3.15 / AES-GCM / SQLiteの配送待ちモデル

1
from sp10 import * from sp02 import show db=connect() show(db,"SELECT * FROM policy ORDER BY destination")
destination | action
partner | warn
public | block
team | allow
2
print(send(db,'team',TEXT)) show(db,"SELECT id,destination FROM outbox ORDER BY id")
allow
id | destination
1 | team
3
print(send(db,'partner',TEXT)) show(db,"SELECT COUNT(*) AS queued FROM outbox")
warn
queued
1
4
print(send(db,'partner',TEXT,override=True)) print(send(db,'partner',TEXT,override=True,reason='approved sample transfer')) show(db,"SELECT id,destination FROM outbox ORDER BY id")
warn
allow_override
id | destination
1 | team
2 | partner
5
print(send(db,'public',TEXT,override=True,reason='requested')) print(send(db,'unknown',TEXT)) show(db,"SELECT COUNT(*) AS queued FROM outbox")
block
block
queued
2
6
show(db,"SELECT destination,action,reason,masked FROM audit ORDER BY id")
destination | action | reason | masked
team | allow |  | owner=EMP-****; sample=EMP-****; embedded=XEMP-0042Z
partner | warn |  | owner=EMP-****; sample=EMP-****; embedded=XEMP-0042Z
partner | warn |  | owner=EMP-****; sample=EMP-****; embedded=XEMP-0042Z
partner | allow_override | approved sample transfer | owner=EMP-****; sample=EMP-****; embedded=XEMP-0042Z
public | block | requested | owner=EMP-****; sample=EMP-****; embedded=XEMP-0042Z
unknown | block |  | owner=EMP-****; sample=EMP-****; embedded=XEMP-0042Z
7
for ident,masked in db.execute("SELECT id,masked FROM audit").fetchall(): db.execute("UPDATE audit SET masked=? WHERE id=?",(re.sub(r'EMP-[0-9]{4}','EMP-****',masked),ident)) show(db,"SELECT DISTINCT masked FROM audit")
masked
owner=EMP-****; sample=EMP-****; embedded=XEMP-****Z
8
show(db,"SELECT COUNT(*) AS attempts,COUNT(DISTINCT digest) AS contents FROM audit") print(hmac.compare_digest(hmac.new(PUBLIC_KEY,TEXT.encode(),hashlib.sha256).hexdigest(),db.execute("SELECT digest FROM audit LIMIT 1").fetchone()[0]))
attempts | contents
6 | 1
True

演習完了