第 7 章 セキュリティモデル
Fayger のセキュリティモデルは二つの軸で構成されます:
- 出所信頼:BuF 成果物自体に署名でき、ロード時に出所と完全性を検証。
- 実行制御:BuF_Instance は実行時、明示的に付与されたケーパビリティだけを使用でき、宣言されないケーパビリティは一切見えない。
二軸はそれぞれロード層とアダプタ層で実現され、第 6 章のエラーモデルと第 4 章の障害分離で補強されます。
7.1 出所信頼:署名とダイジェスト
ダイジェスト
各 Section は BuF_Manifest に digest を宣言します。ロードチェーンの Verify Digest 段で各 Section のダイジェストを再計算し比較:
- いずれか不一致なら
LDR_DIGEST_MISMATCHを返却。 - エラー context に失敗した
section_idを含めます。
Trailer の manifest_digest は同時に Manifest 自身が切り詰めや改変を受けていないことを検証します。
署名スコープ
署名がカバーするバイト範囲:
Header || Manifest_minus_signature || Section_Index
設計意図:
- 署名後に Manifest の任意フィールド(signature ブロック自身を除く)を改変しても署名は失効。
- Section オフセット、長さ、ダイジェストの調整も署名を失効させます(Section_Index が署名範囲内のため)。
- Section 本体自体は署名範囲に直接含まれませんが、各段の
digestが Manifest 内にあるため間接的にカバーされます。
「manifest を署名し、digest が sections を連鎖する」という方式は OCI Image 署名と同じトレードオフ:署名入力サイズが管理可能で検証速度が予測可能。
対応署名アルゴリズム(第一フェーズ)
ed25519ecdsa-p256rsa-pss-sha256
アルゴリズム識別子と公開鍵参照は Manifest の signature ブロックで明示宣言し、ASN.1 / X.509 経由の暗黙交渉を避けます。
署名検証の決定表
| 条件 | 期待結果 |
|---|---|
| 強制署名 ON ∧ 署名なし | Err(LDR_SIGNATURE_FAIL)、理由 MissingSignature |
| 署名あり ∧ 検証失敗 | Err(LDR_SIGNATURE_FAIL)、理由 InvalidSignature |
| 署名あり ∧ 検証成功 | Ok |
| 強制署名 OFF ∧ 署名なし | Ok(開発便宜) |
7.2 強制署名モード
強制署名モード(enforce signature)は LoaderPolicy.require_signature で制御するロードポリシーのスイッチ:
struct LoaderPolicy {
require_signature: bool
trusted_roots: TrustedRootSet
allowed_schema_versions: VersionRange
}
挙動制約:
- ON:BuF は必ず署名を持ち、検証を通過する必要がある。さもなくばロード拒否。
- OFF:署名なしの BuF もロード可(開発便宜)。署名はあるが無効な BuF は拒否(「署名のふり」を許さない)。
リリース時(本番、信頼できる配布チャネル)は設定層で require_signature の既定を true にすることを推奨します。
7.3 信頼ルート管理
interface TrustStore {
current_roots() -> TrustedRootSet
update(roots: TrustedRootSet)
enforce_signature() -> bool
}
更新可視性制約:
- 操作列
Ops(Update(roots)とLoad(buf)の混在)について、各Load(buf)の署名検証で使う信頼ルート集合は、その Load 直前の最新Updateで設定された roots と等しい。 - これにより「ロード途中で root 集合が切り替わる」競合は意味論的に発生しません。
実装戦略:
- 各
LoaderPipeline.loadの入口でTrustStoreのスナップショットを取得し、ロード全体で使用。 - ロード期間中の可変な信頼ルート集合の共有を明示的に拒否。
7.4 実行制御:ケーパビリティセキュリティモデル
アダプタ層は capability-based security(WASI に同じ)を採用。BuF は Manifest でケーパビリティ要求を宣言、Platform_Adapter とホストポリシーが共同で付与を決定します。
形式化:
granted = requested ∩ available ∩ host_policy
denied = requested \ granted
起動ゲート
manifest.required_capabilities \ granted ≠ ∅ の場合:
start()は必ずエラーを返却。- エラー context.missing は差集合。
- インスタンスは Running に入りません。
これは「ケーパビリティ不足時は起動禁止」の硬制約。
既定拒否
- 宣言されないケーパビリティは BuF から見えない。
- Platform_Adapter は「ビットがそれっぽいから通す」ような未宣言ケーパビリティの提供をしてはなりません。
- 認識されない Universal_Instruction カテゴリは一律
ADP_UNSUPPORTED_INSTRUCTIONを返し、「黙って通す」を許しません。
7.5 ケーパビリティ分類と削減ポイント(ホスト別)
| ホストクラス | 典型的に利用可 | 典型的に利用不可 | 注 |
|---|---|---|---|
| デスクトップ | io.*、net.*、ui.*、time、random、crypto、proc.*、host.* | プラットフォームと権限に依存 | ほぼ全集合 |
| サーバー | io.*、net.*、time、random、crypto、proc.* | ui.* 全無効 | GUI なしが既定 |
| ブラウザ | net.fetch、net.websocket、ui.dom、time、random、crypto の部分 | proc.*、ほとんどの io.* | 強い削減 |
| In-App | ホストが明示注入 | 既定で全部無効 | 最も厳格、ホストが最終決定権を持つ |
7.6 セキュリティ障壁としてのリソース分離
リソース分離は安定性要件であると同時にセキュリティ障壁の一部でもあります:
- 単一 BuF_Instance の故障は他のインスタンスに伝搬しない(第 4 章の障害分離性質)。
- クォータ超過は停止を引き起こし、一つのインスタンスがホスト資源を食い尽くすのを防ぐ。
- インスタンス間の RuntimeDataArea は相互に不可視で、データ層でのサイドチャネル情報漏えいを防ぐ。
7.7 セキュリティとエラーの相互作用
署名とケーパビリティ関連の失敗は統一エラーモデルで対外返却:
- 署名失敗:
LDR_SIGNATURE_FAIL、MissingSignature/InvalidSignatureなどの理由付き。 - ケーパビリティ拒否:
ADP_CAPABILITY_DENIED、拒否されたケーパビリティ集合付き。 - 起動ゲート失敗:
ADP_CAPABILITY_DENIEDを再利用。context.missing に差集合。
エラー連鎖は第 6 章と一致:下層エラーは cause に、上層エラーは自身の source_layer を付け、呼び出し側が連鎖を辿って特定可能。
7.8 セキュリティ監査の推奨
監査自体は Fayger の内部範疇ではないが、Fayger のイベントバス、Lifecycle イベント、Loader イベントは外部監査システムに十分なアンカーを提供します:
- ロードチェーン各段の成功 / 失敗イベントは出所検証の監査点。
- Lifecycle イベントは各インスタンスの起動 / 停止 / 終了タイムラインを記録。
- ケーパビリティ削減結果はセキュリティ判断の監査点。
- 署名失敗、ケーパビリティ拒否、クォータ超過のイベントは外部 SIEM / 監査パイプラインで購読可能。
