バックアップの復元と整合性確認
保存世代の内容、設定変更の影響、復旧先の業務データを一続きで確認します。
説明
バックアップの設定が保護されていても、設定変更、内容の破損、復旧手順の不足によって戻せない場合があります。設定と保存データ、復旧先を順に確認します。
固定の注文DBをコピーした後で元データを変更します。暗号文の改変検査と別DBへの復旧を行い、構造検査だけでなく注文の件数と合計も照合します。
保存世代の内容、設定変更の影響、復旧先の業務データを一続きで確認します。
1保存した世代と元データを比較する
このページでは注文1が100、注文2が200の状態から始めます。
from sp22 import *
from sp02 import show
lab=Backup()
show(lab.source,"SELECT * FROM orders ORDER BY id")
print(hashlib.sha256保存した世代と元データを比較する(lab.cipher).hexdigest())バックアップのハッシュを記録しました。これは保存バイトの同一性に使う値で、業務データが正しいことの判定とは別です。
2取得後に元データを変更する
注文2を元DBから削除します。
lab.source.execute("DELETE FROM orders WHERE id=2");lab.source.commit()
show取得後に元データを変更する(lab.source,"SELECT * FROM orders ORDER BY id")
show(lab.snapshot,"SELECT * FROM orders ORDER BY id")元DBは1行、コピーは2行です。どの時点のデータへ戻るのかが具体的に確認できます。
3保持設定の変更履歴を残す
新規取得に使う設定値を100から50へ変えた固定例です。
lab.db.execute("INSERT INTO audit VALUES (20,'backup-admin','retention',100,50)")
lab.db.execute("UPDATE config SET value=50 WHERE name='retention'")
show保持設定の変更履歴を残す(lab.db,"SELECT * FROM audit")
show(lab.db,"SELECT retain_until FROM backup")既存b7の期限は100のままです。既存世代への適用と、今後作る世代の既定値を分けて確認します。
4暗号文の変更を検出する
一つのバイトを反転した試料です。
changed=bytes([lab.cipher[0]^1])+lab.cipher[1:]
print(hashlib.sha256(changed).digest()==hashlib.sha256(lab.cipher).digest())
try:
lab.restore暗号文の変更を検出する(changed)
except InvalidTag as e:
print(type(e).__name__)ハッシュは不一致で、AES-GCMもInvalidTagになります。認証に失敗したデータをそのまま復旧先へ書き込みません。
5別DBへ復旧して構造を検査する
元DBとは別の接続へ復旧します。
restored=lab.restore()
print(restored is lab.source)
show(restored,"PRAGMA integrity_check別DBへ復旧して構造を検査する")別接続であり、構造検査はokです。実復旧ではネットワークや資格情報も隔離し、業務への接続を段階的に戻します。
6件数と業務上の集計値を照合する
注文の件数・合計と個々の値を確認します。
show(restored,"SELECT COUNT(*) AS orders,SUM件数と業務上の集計値を照合する(amount) AS total FROM orders")
show(restored,"SELECT * FROM orders ORDER BY id")2件、合計300です。構造が壊れていないだけでなく、この保存世代に期待する注文内容も確認できました。
7元DBへの意図しない上書きがないことを確認する
復旧後も元DBの件数を読み直します。
show元DBへの意図しない上書きがないことを確認する(lab.source,"SELECT COUNT(*) AS source_orders FROM orders")
restored.close()元DBは1件のままです。復旧先を分けることで、確認前に現行データを上書きせず比較できます。復旧時間の目標は、別途実際の手順を通して測定します。
まとめ
設定変更が既存世代へ及ぶ範囲を確認します。
保存バイトの検査と復旧を実施します。
構造と業務上の値の両方を照合します。
操作履歴と解説を振り返れます。
Python 3.15 / SQLite backup / AES-GCM / 固定の保管権限モデル
from sp22 import *
from sp02 import show
lab=Backup()
show(lab.source,"SELECT * FROM orders ORDER BY id")
print(hashlib.sha256(lab.cipher).hexdigest())id | amount 1 | 100 2 | 200 bc1eb0b90c67cd366a1bf7a67769e025925325dece77834dff45b4e68dd35550
lab.source.execute("DELETE FROM orders WHERE id=2");lab.source.commit()
show(lab.source,"SELECT * FROM orders ORDER BY id")
show(lab.snapshot,"SELECT * FROM orders ORDER BY id")id | amount 1 | 100 id | amount 1 | 100 2 | 200
lab.db.execute("INSERT INTO audit VALUES (20,'backup-admin','retention',100,50)")
lab.db.execute("UPDATE config SET value=50 WHERE name='retention'")
show(lab.db,"SELECT * FROM audit")
show(lab.db,"SELECT retain_until FROM backup")t | actor | setting | before_value | after_value 20 | backup-admin | retention | 100 | 50 retain_until 100
changed=bytes([lab.cipher[0]^1])+lab.cipher[1:]
print(hashlib.sha256(changed).digest()==hashlib.sha256(lab.cipher).digest())
try:
lab.restore(changed)
except InvalidTag as e:
print(type(e).__name__)False InvalidTag
restored=lab.restore()
print(restored is lab.source)
show(restored,"PRAGMA integrity_check")False integrity_check ok
show(restored,"SELECT COUNT(*) AS orders,SUM(amount) AS total FROM orders")
show(restored,"SELECT * FROM orders ORDER BY id")orders | total 2 | 300 id | amount 1 | 100 2 | 200
show(lab.source,"SELECT COUNT(*) AS source_orders FROM orders")
restored.close()source_orders 1
演習完了