一覧SC-01-1 · 守る対象とセキュリティ特性

情報セキュリティの3要素

「セキュリティの問題」という一括りではなく、観測した記録から失われた特性と追加で必要な証拠を説明します。

説明

同じ注文システムでも、他人の注文が見える、金額が書き換わる、必要なときに使えない、という問題は守る対象が異なります。機密性は許可された相手だけが情報を読めること、完全性は不正な変更を防ぐこと、可用性は必要なときに利用できることに関わります。

2件の注文と4件の固定アクセス記録をSQLiteで調べます。注文の所有者と閲覧者、変更前後の金額、503応答、申告した主体と認証済み主体、欠落した要求IDを順に照合します。

「セキュリティの問題」という一括りではなく、観測した記録から失われた特性と追加で必要な証拠を説明します。

1注文と所有者

この試料では注文は所有者本人だけが閲覧できる契約です。aliceは注文7、bobは注文8を持ちます。

from sc01 import connect固定業務資料を読み込む db = connect("properties")独立した注文DBを作る print(db.execute("SELECT * FROM orders ORDER BY id注文・所有者・金額を一覧にする").fetchall())

注文7は100、注文8は200です。この所有関係をアクセス記録のactorと比較します。

2応答成功と閲覧許可は別

HTTP 200の記録を注文の所有者と結合し、他人の注文を返したものを抽出します。

print(db.execute("SELECT r.id,r.actor,o.owner,r.returned_bytes要求・閲覧者・所有者・返却量を読む FROM requests r JOIN orders o ON o.id=r.resource WHERE r.status=200 AND r.actor<>o.owner所有者以外への成功応答に絞る").fetchall())

r2でaliceへbobの注文140バイトが返っています。処理が200で終わっていても、機密性を守れているとはいえません。

3比較元のある変更を調べる

注文7の金額を999へ変え、保存してある比較元と差分を出します。ここでは変更を正当化する承認記録はありません。

db.execute("UPDATE orders SET amount=999 WHERE id=7試料の金額を変更する") print(db.execute("SELECT o.id,b.amount,o.amount比較元との差を抽出する FROM orders o JOIN original b USING(id) WHERE o.amount<>b.amount").fetchall())

注文7が100から999へ変わっています。完全性の確認には、現在値だけでなく、比較元や変更の権限・承認も必要です。

4失敗応答を集計する

4件の要求のうち503が何件あるか確認します。503は要求時にサービスを提供できなかった記録です。

print(db.execute("SELECT COUNT(*)観測した要求数を数える,SUM(status=503)503の件数を数える,ROUNDこの試料内の割合を求める(100.0*SUM(status=503)/COUNT(*),1) FROM requests").fetchone())

4件中1件、25.0%が503です。この4件の比率であり、長期間の稼働率や停止時間の実測とは異なります。

5申告した主体を認証結果と照合する

claimed_actorは要求側が名乗った値、actorはこの固定資料で認証済みの主体です。両者が異なる記録を探します。

print(db.execute("SELECT actor,claimed_actor認証済み主体と申告値を並べる FROM requests WHERE actor<>claimed_actor一致しない要求に絞る").fetchall())

aliceがadminを名乗った記録があります。申告値をそのまま管理者の権限判定へ使うと、主体の確認を取り違えます。

6追跡できない要求を探す

要求IDが欠落した記録は、別システムのログと結び付けにくくなります。

print(db.execute("SELECT actor,resource,status欠落した要求の内容を読む FROM requests WHERE id IS NULL要求IDがない行を探す").fetchall())

aliceの注文7への要求にIDがありません。actorが残っていても、要求単位の追跡に不足があります。ログに名前があるだけで否認防止まで保証できるわけではありません。

7復元しても漏えい記録は残る

比較元から注文7を100へ戻し、他人へ返した記録を再び確認します。

db.execute("UPDATE orders SET amount=比較元の金額へ戻す(SELECT amount FROM original WHERE id=orders.id)") print(db.execute("SELECT id,amount FROM orders復元後の金額を読む ORDER BY id").fetchall()) print(db.execute("SELECT returned_bytes FROM requests漏えいした要求の記録を再確認する WHERE id='r2'").fetchone())

金額は戻りますが、r2で返した140バイトの事実は消えません。データ復元は、すでに読まれた情報を回収する操作ではありません。

まとめ

成功応答でも閲覧権限に反する場合があります。

改変の検出には比較元と変更の権限を、停止の評価には観測範囲を確認します。

主体の申告・認証結果・要求追跡の証拠を混同しません。

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

Python 3.15 / SQLite / 固定業務・監査資料

1
from sc01 import connect db = connect("properties") print(db.execute("SELECT * FROM orders ORDER BY id").fetchall())
[(7, 'alice', 100), (8, 'bob', 200)]
2
print(db.execute("SELECT r.id,r.actor,o.owner,r.returned_bytes FROM requests r JOIN orders o ON o.id=r.resource WHERE r.status=200 AND r.actor<>o.owner").fetchall())
[('r2', 'alice', 'bob', 140)]
3
db.execute("UPDATE orders SET amount=999 WHERE id=7") print(db.execute("SELECT o.id,b.amount,o.amount FROM orders o JOIN original b USING(id) WHERE o.amount<>b.amount").fetchall())
[(7, 100, 999)]
4
print(db.execute("SELECT COUNT(*),SUM(status=503),ROUND(100.0*SUM(status=503)/COUNT(*),1) FROM requests").fetchone())
(4, 1, 25.0)
5
print(db.execute("SELECT actor,claimed_actor FROM requests WHERE actor<>claimed_actor").fetchall())
[('alice', 'admin')]
6
print(db.execute("SELECT actor,resource,status FROM requests WHERE id IS NULL").fetchall())
[('alice', 7, 200)]
7
db.execute("UPDATE orders SET amount=(SELECT amount FROM original WHERE id=orders.id)") print(db.execute("SELECT id,amount FROM orders ORDER BY id").fetchall()) print(db.execute("SELECT returned_bytes FROM requests WHERE id='r2'").fetchone())
[(7, 100), (8, 200)]
(140,)

演習完了