はじめに
このガイドでは、OZero Security のインストールから最初の保護設定までを順に案内します。セキュリティの専門知識がなくても、約3分で基本設定を完了できます。
概要
OZero Security は、一般的なハッキングツールが到達しにくい Native C++ レイヤーでセキュリティロジックを実行して Unity ゲームを保護します。Unity エディター内のダッシュボードでモジュールを有効化するだけで、すぐに使える保護機能が動作します。コア保護を動かすのに、手動のシーン設定や定型コードは必要ありません。
- ビルド整合性チェック(アプリ改ざん検知)
- スピードハック・タイムハック検知
- メモリインジェクション監視
- 暗号化されたインゲーム変数型(Secure Types)
- 暗号化されたセーブファイルと PlayerPrefs
- 有効化した検出器は SDK 起動時に自動的に準備されます — シーン配置や定型コード(boilerplate)の呼び出しは不要です。
- セキュリティ設定はビルド時に保護されるため、通常のプレイヤー向け配布物に平文の設定が露出しません。
- Native C++ ランタイムガードが、管理対象の Unity コードの外側で追加の検証レイヤーを提供します。
- 脅威への対応は SDK ポリシーと Pro テレメトリで一元化されており、実装の詳細を露出せずに現場調査が容易になります。
1
パッケージのインポート
Unity エディターを開き、OZero Security パッケージをインポートします。Unity Package Manager から、または .unitypackage ファイルをダブルクリックしてインポートできます。
表示される Import Unity Package ダイアログで、すべての項目にチェックが入った状態で Import をクリックします。必要なスクリプト、ネイティブプラグイン、エディターツールがプロジェクトに自動的に追加されます。
2
ダッシュボードを開く
インポートが完了したら、Unity メニューバーから OZero Security Dashboard を開きます:
カスタムエディターウィンドウが開きます。これがすべての OZero セキュリティモジュールを制御する中央パネルです。Project ヒエラルキーは一切操作する必要がなく、すべてここで管理します。
3
モジュールの有効化
ダッシュボード内に、トグルスイッチ付きの利用可能なセキュリティモジュール一覧が表示されます。使用したいモジュールを有効化してください。推奨の初期構成は以下のとおりです。
セキュリティプリセット
まずプリセットを選び、プロジェクト固有の方針が必要な場合だけ個別モジュールを調整してください。一般的なライブゲームでは、保護性能、実行負荷、誤検知リスクのバランスがよい Standard から始めることを推奨します。
| プリセット | 推奨用途 | ポリシー概要 |
|---|---|---|
| Low | プロトタイプ、開発ビルド、初期QA | 軽量な基本チェックだけを有効にします。テスト環境が早い段階でブロックされないよう、プラットフォームネイティブ検査と強制終了ポリシーを緩めます。 |
| Standard | ほとんどのリリース済みゲームに推奨される既定値 | コア保護、起動時検証、ランタイム再検証、エミュレーター検査、推奨IL2CPPファイル範囲を有効化し、互換性と保護レベルのバランスを取ります。 |
| Strict | 高リスクのライブサービス、PvP、競技性の高いビルド | 最大範囲の検査を有効にし、より多くの失敗を致命的な違反として扱います。プラットフォーム、署名、ストア配布フローを十分に検証してから使用してください。 |
| モジュール | 機能 | 推奨 |
|---|---|---|
| Build Integrity Validator | アプリバイナリが改変されたかを検知 | 推奨 |
| Speed Hack Detector | 時間操作系チートを検知 | 推奨 |
| Injection Detector | メモリフッキングツールを監視 | 推奨 |
| Install Source Validator | 不正な APK をブロック(Android のみ) | 任意 |
「Auto Setup」ボタンを押す必要はありません。ダッシュボードで有効化したいモジュールをトグルし、OZeroSecurityConfig アセットを保存してください。プレイヤー起動時、SDK がゲームプレイ開始前に有効な検出器を自動で準備します。
OZeroSecurityConfig アセットを保存すれば、次回起動時にすべての有効モジュールが自動生成されます。シーン配置やボタン操作は不要です。
ライセンスモデル — Standard / Plus / Pro
OZero Security は3つのティアで提供されます。Standard は共有ネイティブモジュールを使う完全サーバーレスです。Plus はサーバーレスのまま、マニフェストと Bundle ID で紐付けたアプリ別 Native Variant パッケージを追加します。Pro は Plus を含み、Cloud Telemetry、Signed Time、リモートポリシー、attestation、デバイス数上限などのサーバー側機能を解放します。
| 項目 | Standard | Plus | Pro |
|---|---|---|---|
| ライセンスキー | —(なし) | OZ-PLS-XXXX ×6 |
OZ-PRO-XXXX ×6 |
| 起動時のネットワーク | なし — 完全オフライン | ランタイムサーバー不要。ポータルからのダウンロードのみ | デバイスごとに1回の POST /v1/activate、以降はキャッシュ |
| 9つの検出器モジュール | 全9種 — Build / Speed / Inject / Device / Source / Physics / Memory / File / PlayerPrefs | 全9種(ローカルモジュールは同一) | 全9種(Standard と同一) |
| Native Variant | 共有ネイティブモジュール | アプリ別 Variant + マニフェスト紐付け | 含む |
| Cloud Telemetry | オフ(何もしない) | オフ(サーバーレス) | オン — abort イベントを /v1/telemetry へ送信 |
| Signed Time(時計改ざん対策) | オフ — WebTime は HTTPS HEAD のみ使用 |
オフ — Standard と同じ | オン — 電子署名された /v1/time |
| デバイスごとの上限 | 無制限(キーなし、強制なし) | プロジェクト紐付けライセンス。ランタイムのデバイス上限なし | 既定5 / 調整可能 |
| ソースコードアクセス | 管理対象 C# のみ | 管理対象 C# のみ | 管理対象 C# のみ |
OZeroLicenseConfig を通じてサーバー機能を有効化します。
Plus / Pro ライセンスキーの登録
Standard ティアにはセットアップが不要です。Plus または Pro では、ScriptableObject アセットを1つ追加し、購入後に受け取ったキーを貼り付けます。Plus はプロジェクト紐付けの Variant 検証とポータルダウンロードにキーを使用し、Pro はさらにランタイムのサーバーアクティベーションにも使用します。
1. Config アセットの作成
OZero Security の Config & Dashboard(メニュー: OZero Security → Security → Config & Dashboard)を開き、License & Server セクションを見つけて Create OZeroLicenseConfig をクリックします。アセットが作成され、正しい Resources/ フォルダーへ自動配置されます — 手動のドラッグ&ドロップは不要です。
Assets → Create → OZero → License Config から手動作成することもできます — アセットが必ず Resources/ フォルダー配下に置かれ、名前が正確に OZeroLicenseConfig(大文字小文字を区別)であることを確認してください。
2. Inspector フィールドの入力
| フィールド | 必須対象 | 説明 |
|---|---|---|
| tier | 全ティア | ドロップダウンから Standard、Plus、Pro を選びます。Standard は共有ネイティブモジュールを使用します。Plus はプロジェクト紐付けの Variant マニフェストが必要です。Pro は Plus を含み、サーバー機能を有効化します。 |
| licenseKey | Pro | メールで受け取ったキーです。Plus キーは OZ-PLS-...、Pro キーは OZ-PRO-... を使用します。これを空のままにすると、ティアフィールドが Plus や Pro でも SDK は Standard/サーバーレスとして動作します。 |
| appIdentifier | 自動送信 | SDK はアクティベーション時に Unity の Application.identifier を appIdentifier として送信します。サーバーはこの値をライセンスに登録されたバンドル / パッケージ ID と照合するため、Player Settings の Identifier が発行済みキーと一致していることを確認してください。 |
| serverBaseUrl | Pro | 既定は https://api.ozero.security です — OZero サポートからプライベートエンドポイントの案内がない限りそのままにしてください。リリースビルドでは HTTPS が必須です。末尾のスラッシュは自動的に除去されます。 |
| serverPublicKeyHex | Pro | OZero ライセンスサーバーの32バイトの電子署名公開鍵(64桁の16進数)です。SDK がアクティベーショントークンの署名検証に使用します(Phase 1.5 / N-1 ハードニング)。空のままにすると署名検証は黙ってスキップされます — 移行期のビルドでのみ行い、本番では必ずこの値を設定してください。正規の16進文字列は購入メールから取得します。 |
| tokenTtlSeconds | 任意 | キャッシュされたアクティベーション結果をオフライン時に信頼する時間(秒)です。既定は 604800(7日)です。期限切れ後も SDK は動作し続けますが、サーバー専用機能(テレメトリ / 署名時刻)は次回のアクティベーション成功までオフになります。 |
| offlineProPolicyMode | Pro | デバイスがオフラインの間、署名済みの Pro ポータル遮断ポリシーをどのように適用するかを制御します。推奨値は ApplyCachedBlockPolicies です。古いポリシーを拒否する必要があるオンライン専用ゲームだけ RequireFreshPolicy を使用してください。IgnoreCachedBlockPolicies は旧バージョン互換モードで、ライブビルドでは推奨しません。 |
| activationTimeoutSeconds | 任意 | SDK が /v1/activate を待ってからキャッシュ済み権限へフォールバックするまでの最大時間(秒)です。既定は 6.0 です。アクティベーション呼び出しがシーン読み込みをブロックすることはありません — これはバックグラウンドの Task がタイムアウトをログするまでの待機時間を制限するだけです。 |
| enableLog | 任意 | true の場合、ライセンスフローのイベントが OZeroSecLog を通じて出力されます(キャッシュヒット / アクティベーション成功 / タイムアウト / 電子署名不一致)。既定は true で、ログを静かにしたい場合は出荷時にオフにしてください。 |
3. ビルドと確認
コード変更は不要です。OZeroLicenseBootstrap が [RuntimeInitializeOnLoadMethod(AfterAssembliesLoaded)] で自身を接続し、アプリ起動時にアセットを読み取ります。初回起動時に Player ログで [OZeroLicense] activated; tier=pro caps=5 のような行を確認してください。Pro 設定があるのに [OZeroLicense] Standard / serverless mode. と表示される場合は、アセットが Resources/ フォルダー配下にあり、名前が OZeroLicenseConfig(拡張子なし、リネーム接尾辞なし)であることを再確認してください。
サーバーアクティベーションフロー
アクティベーションフローはアプリ起動時にバックグラウンドで実行されます。SDK がこれによってシーン読み込みをブロックすることはありません — 6秒のタイムアウト時でもキャッシュ済み権限(または Standard フォールバック)が使われるため、プレイヤーが HTTP を待って黒画面で固まることはありません。
起動シーケンス
- SDK は起動時にライセンスランタイムを自動初期化します。
- Standard と Plus はランタイムサーバー呼び出しなしで続行します。
- Pro はバックグラウンドで軽量なアクティベーション要求を送信します。
- アクティベーションに成功すると、telemetry、signed time、attestation などの Pro サーバー機能が利用可能になります。
- アクティベーションが失敗、期限切れ、タイムアウトしても、プレイヤーにエラーを表示せず Standard モードでゲームプレイを継続します。
通信で送られる内容
アクティベーション要求は小さな JSON POST です。必須フィールドは licenseKey、deviceId、sdkVersion、platform です。appIdentifier、companyName、productName、webglOrigin は Unity が空でない値を提供した場合のみ追加されます。デバイス ID の取得元は OZeroLicenseRuntime.DeviceIdProvider で上書きできます。
POST https://api.ozero.security/v1/activate
Content-Type: application/json
{
"licenseKey": "OZ-PRO-XXXX-XXXX-XXXX-XXXX-XXXX-XXXX",
"deviceId": "<DeviceIdProvider result; default SystemInfo.deviceUniqueIdentifier>",
"sdkVersion": "<OZeroSdkVersion.ManagedVersion>",
"platform": "<android | ios | windows | macos | linux | webgl | ...>",
"appIdentifier": "<Application.identifier>",
"companyName": "<Application.companyName>",
"productName": "<Application.productName>",
"webglOrigin": "<WebGL origin only>"
}
サーバーは、JWT 形式の signedToken(header.payload.signature、base64url、パディングなし)、解決された tier、capabilities 配列、serverFeaturesEnabled フラグ、そして(任意で)expiresAt(unix-ms)を含む JSON ボディで応答します。SDK は serverPublicKeyHex を用いて signedToken に対し電子署名検証を実行し、それを通過した場合にのみ権限を受け入れます — それ以外はすべてフェイルクローズです。
グレースフルデグラデーション
サーバーメンテナンス、ネットワークタイムアウト、ライセンス期限切れ、停止、失効、バンドル不一致は改ざんとして扱われません。これらは Pro 専用機能を Standard/サーバーレスモードへ下げ、プレイヤーのセッションは維持されます。ビルド不一致、ブロック済みビルド、インジェクション、デバッガー検知といった確定した改ざん状態は、設定された脅威応答ポリシーに従います。
await OZeroLicenseRuntime.Initialize(); を呼び、OZeroLicenseRuntime.Entitlement?.cachedAtMillis を確認してください。直近数秒以内の値ならサーバーが新しく応答したことを意味し、それより古ければキャッシュで動作中です。
オフライン動作
OZero は、ネットワーク状態に関わらずプレイヤーが常にゲームを起動できるよう設計されています。正確な挙動はティアによって異なります:
Standard — 常にオフライン
サーバーへは一切接続しません。9つの検出器モジュールはすべて劣化なく動作します。ライセンスランタイムは IsServerless = true と HasEntitlement = false を設定します。OZeroTelemetryReporter はアタッチされますが、すべてのイベントで何もしません。
Pro — TTL 内はオフライン可
あるデバイスで最初の /v1/activate が成功すると、権限が PlayerPrefs にキャッシュされます(デバイス紐付けキーで暗号化 — 下記のキャッシュセキュリティ参照)。以降の起動ではネットワーク呼び出しが始まる前にキャッシュが同期的に読み込まれるため、プレイヤーがオフラインでも SDK はどのティアか、どの機能が解放されているかを把握できます。
キャッシュ済み権限は、アクティベーション時に書き込まれた cachedAtMillis スタンプから tokenTtlSeconds の間信頼されます。既定は7日(604800)です。ずっとオフラインだったデバイスで TTL が切れると、キャッシュは破棄され、SDK は次回のアクティベーション成功まで Standard 相当の機能に劣化します。検出器は動作を続け、テレメトリ送信と署名時刻検証のみがオフになります。
Pro — 署名済みオフライン遮断ポリシー
Graceful degradation は、ライセンス、ネットワーク、サーバー可用性の問題に対する動作です。ポータルで明示的に遮断したビルドがオフラインで許可される、という意味ではありません。Pro アクティベーションが成功すると、サーバーは現在のポータル遮断ポリシーをアクティベーショントークンに署名して含め、SDK はそのポリシーを entitlement とは別にキャッシュします。
推奨の ApplyCachedBlockPolicies モードでは、署名済みポリシーが有効な間、プレイヤーが機内モードで起動しても、遮断された manifest hash、SDK バージョン、アプリバージョンは Build Integrity によって拒否されます。ポリシーは署名トークンの TTL に従うため、ポータルで遮断ルールを変更した後は一度オンラインでアクティベーションしてください。
| 状態 | 検出器 | Telemetry | Signed Time |
|---|---|---|---|
| オンライン、新規アクティベーション | 全9種オン | オン | オン |
| オフライン、キャッシュ < TTL | 全9種オン | キュー保持(次回オンライン時に送信) | WebTime HTTPS HEAD にフォールバック |
| オフライン、キャッシュ > TTL | 全9種オン | オフ(劣化) | オフ(劣化) |
| キャッシュなし(初回起動+オフライン) | 全9種オン | 初回オンライン起動までオフ | 初回オンライン起動までオフ |
トラブルシュート
すべてのライセンスイベントは OZeroSecLog を通じて記録され、既定では Unity の Debug.Log にルーティングされます(OZeroSecurityConfig で設定可能)。Player ログを [OZeroLicense] プレフィックスで絞り込むと起動時の判断が、[OZeroTelemetry] でレポーターの動作が確認できます。よくある症状と対処:
| 症状(ログ行) | 考えられる原因 | 確認すべき点 |
|---|---|---|
[OZeroLicense] Standard / serverless mode. |
アセット欠落、または tier=Standard、またはキーが空 | OZeroLicenseConfig.asset が Resources/ フォルダー配下にあり、名前が正確に OZeroLicenseConfig、tier=Pro、かつ licenseKey が空でないことを確認してください。 |
/v1/activate failed: 401: invalid_key |
キーの打ち間違い、またはティアのプレフィックス違い | 元の購入メールからキーを貼り直してください。書式は大文字小文字を区別し、ダッシュは必須で、プレフィックス OZ-PRO- はアセットのティアドロップダウンと一致している必要があります。 |
/v1/activate failed: 403: bundle_mismatch |
appIdentifier の不一致 |
サーバー側のライセンス記録は、キーを特定のバンドル / パッケージ ID に紐づけます。Player Settings の Application.identifier がライセンスに登録された ID と一致していることを確認してください。 |
activation token signature verification failed |
serverPublicKeyHex の誤り、または MITM |
アセット内の16進文字列を、購入メールの正規 pubkey と1文字ずつ、64桁すべて照合してください。正しいのに失敗する場合は、企業プロキシ/MITM 機器を疑い、直接のモバイルデータ接続で試してください。 |
/v1/activate timed out |
ネットワーク遅延 / ファイアウォール | SDK は自動でキャッシュにフォールバックします — 問題になるのは初回起動 / キャッシュなしの場合のみです。デバイスが https://api.ozero.security/health に到達できるか確認し、高遅延地域で運用する場合は activationTimeoutSeconds を上げてください。 |
cached entitlement past TTL; clearing. |
プレイヤーがオフライン > TTL | 想定どおりです。検出器は動作し続け、テレメトリ / 署名時刻は次回オンライン起動までオフになります。利用者が日常的に7日以上オフラインで遊ぶ場合は tokenTtlSeconds を上げてください。 |
cache hit; tier=pro on a different machine than expected |
デバイス指紋の変化 | SystemInfo.deviceUniqueIdentifier がローテーションすると(一部の Android ROM / OS リセット)、v2 キャッシュが読めなくなり、SDK は単純に再アクティベーションします。ユーザー操作は不要で、次回オンライン起動で回復します。 |
enableLog = true のままビルドを出荷しないでください。ライセンスフローのログはティア / 機能状態を明かしますが、これは露出しても問題ありません。ただし検出器の内部を静かに保つため、グローバルの OZeroSecurityConfig.enableLog も併せて無効にしてください。
プロジェクト設定
個別のセキュリティモジュールを調整する前に、ネイティブプラグイン、ストアビルド、プラットフォーム検証に影響するUnity Player Settingsを確認してください。
最小ビルドターゲット
| プラットフォーム | 最小ターゲット | 説明 |
|---|---|---|
| iOS | 12.0+ |
iOS ビルドでは Project Settings > Player > iOS > Target minimum iOS Version を 12.0 以上に設定してください。OZero はこの PlayerSettings 値を上書きしないため、アプリのサポート方針に合わせて維持してください。 |
| Android | API 21+ |
Androidビルドでは、Project Settings > Player > Android > Minimum API LevelをAndroid 5.0 Lollipop (API level 21)以上に設定してください。ストアリリースビルドではIL2CPPとARM64の使用を推奨します。 |
Android ProGuard / R8 設定
OZero Security は別途の Java SDK パッケージを必要としません。ただし Minify、ProGuard、R8 を有効化した Android リリースビルドでは、Unity の Java ブリッジとプロジェクトで使用するカスタム Android ブリッジクラスを保持する必要があります。これにより、パッケージ情報、インストール元、APK 署名証明書チェック、ブートアセット読み込みに必要な JNI 呼び出しが、難読化後も安定して動作します。
proguard-user.txt に追加してください。Minify を使用しない場合、追加の ProGuard 設定は不要です。
# OZero Security - Unity Android ProGuard/R8 keep rules
-keep class com.unity3d.player.UnityPlayer { *; }
-keep class com.unity3d.player.UnityPlayerActivity { *; }
-keep class com.unity3d.player.UnityPlayerGameActivity { *; }
-keep class com.unity3d.player.UnityPlayerForActivityOrService { *; }
-keepattributes *Annotation*,InnerClasses,EnclosingMethod,Signature
# If your game adds custom Java/Kotlin bridge classes that OZero or your code
# calls through AndroidJavaClass / AndroidJavaObject, keep those classes too.
# Replace the package below with your own bridge package.
# -keep class com.yourcompany.yourgame.bridge.** { *; }
libOZeroSecurity.soの名前変更・削除・再パッケージをしないでください。プラグインはAssets/OZeroSDK/Plugins/Android/arm64-v8a配下に保持し、32ビットビルドを配布する場合はarmeabi-v7aも維持してください。- Build Integrity > Check Platform Native と Android SHA Keys を有効にしている場合は、Minify/R8 適用後の最終的な署名済み APK または AAB で必ずテストしてください。デバッグキーストアの指紋とリリースキーストアの指紋は異なります。
- Minify を有効にした後にのみ、Android ログで JNI 検索失敗、インストール元検知失敗、APK 署名チェックの結果が空になる場合は、まずカスタムブリッジの keep ルールを確認してください。
- ストア配布用ビルドは、IL2CPP、リリース署名、
Android Sha Keysに登録した期待される Android SHA-256 指紋、そして最低1台の実機でのクリーン起動テストを基準に検証してください。
5
OZeroSecurityConfig の設定
OZeroSecurityConfig ScriptableObject アセットはパッケージのインポート時に含まれます。Project ウィンドウで選択して、すべてのセキュリティモジュール設定を確認・調整できます。Config はシングルトンで、ランタイムでは OZeroSecurityConfig.Instance でアクセスします。
一般設定
これらの最上位フィールドは、すべてのモジュールに共通で適用されます。
| フィールド | Type | 既定値 | 説明 |
|---|---|---|---|
| developerSecret | string | — | 暗号化キーの導出に使われる固有のパスフレーズです。ゲームごとに固有の値を設定し、秘密に保ってください。リリース後に変更すると、既存のセーブデータが読み取れなくなります。 |
| enableLog | bool | false | Enable Debug Logs を有効にすると、SDK初期化、設定読み込み、ライセンス/テレメトリの流れ、検知イベントの状態が Unity Console と Player ログに出力されます。開発やQAでは有用ですが、検知フローやモジュール状態が露出する可能性があるため、本番ビルドでは通常無効にしてください。 |
| enableFailureDiagnostics | bool | false | Enable Failure Diagnostics を有効にすると、セキュリティ違反発生時にローカル診断ファイルを Application.persistentDataPath に保存します。ファイルにはモジュール名、ハッシュ、デバイス状態、インストーラーパッケージ名、ランタイム設定の一部が含まれる可能性があるため、QAまたはカスタマーサポート時のみ有効にしてください。プラットフォーム別の既定保存先:
|
Developer Secret を設定してください。既定値は使わず、リリース後には変更しないでください。
応答設定
いずれかのセキュリティモジュールが検知イベントを発生させたときの動作を制御します。
| フィールド | Type | 既定値 | 説明 |
|---|---|---|---|
| forceQuitOnDetection | bool | true | forceQuitOnDetection は、確定した脅威を検知したときにアプリを自動終了するかを決めます。Standard と Strict プリセットでは既定で有効になっており、管理コード側のコールバックがパッチされたり存在しない場合でも、内部fallback receiverが応答ポリシーを強制できます。アプリを終了せずに検知状況を観察する必要がある、管理されたQAフローでのみ無効にしてください。 |
ビルド整合性設定
改変されたゲームファイル、デバッガーの接続、不審な実行環境を検知するビルド整合性検証器を設定します。
| フィールド | Type | 既定値 | 説明 |
|---|---|---|---|
| Activate Build Integrity | checkbox | On | Build Integrity モジュールを有効化します。 |
| validateOnStartup | bool | true | ゲーム起動直後にビルド整合性チェックを実行します。 |
| validateInEditor | bool | false | Unity エディターでも検証を実行します(テストには便利ですが、通常の開発中は無効を推奨)。 |
| enablePeriodicValidation | bool | true | ゲーム実行中も整合性検証を繰り返します。起動時1回の検証だけで十分な場合を除き、有効化を推奨します。 |
| periodicCheckInterval | float | 300 s | ゲーム実行中に定期的なセキュリティチェックを実行する間隔(秒)です。 |
| periodicCheckJitterPercent | float | 35% | 検証周期にランダムなジッターを加え、攻撃者が正確な検証タイミングを予測しにくくします。例: 300秒に35%のジッターなら、おおよそ195〜405秒の間で実行されます。 |
| timingAnomalyConsecutiveRequired | int | 7 | デバッガーのタイミングドリフトを違反として扱う前に、タイミングのみの異常をどれだけ蓄積する必要があるかを制御します。強いデバッガー信号は依然として即座に失敗させられます。 |
| timingAnomalyWindowSeconds | float | 900 s | タイミングのみの異常を蓄積する時間ウィンドウです。長いほど寛容で、Strict はより短いウィンドウを使用します。 |
| timingAnomalyFrameHitchSuppressionSeconds | float | 20 s | シーン読み込み、シェーダーコンパイル、GC、OS スケジューリングの停滞といった大きなフレームヒッチの後に、タイミングのみのデバッガーチェックを抑制します。 |
| checkAssemblyHash | bool | true | ビルド整合性の一環として、コンパイル済み DLL アセンブリのハッシュ検証を有効化します。 |
| checkDebugger | bool | true | ランタイムにデバッガーがプロセスへ接続されているかを検知します。 |
| failOnDebugBuild | bool | false | Unity のデバッグビルドを違反として扱います(リリースビルドで推奨)。 |
| checkPlatformNative | bool | true | エミュレーターや非標準環境で実行されている兆候を確認します。 |
| failIfManifestMissing | bool | true | OZeroIntegrityManifest.ozero ファイルが存在しない場合に違反として扱います。攻撃者がマニフェストを削除して整合性チェックを回避できないよう、有効のままにしてください。 |
| failIfAssemblyHashBlobMissing | bool | true | マニフェスト内にバンドルされたアセンブリハッシュブロブが存在しない場合に違反として扱います。 |
| requireCodeSignature (Windows) | bool | false | メイン実行ファイルがコード署名されていることを要求します。Windows のみ。 |
| blockVirtualMachine (Windows) | bool | false | 仮想マシン内でのゲーム実行をブロックします。Windows のみ。 |
| blockHyperV (Windows) | bool | false | Hyper-V VMBusシグナルをブロックします。WSL2、Docker Desktop、Windows Sandboxもブロックされる可能性があるため慎重に使用してください。 |
| blockNetworkProxies (Windows) | bool | false | Wireshark、Fiddler、Charles、HTTPDebuggerなどのネットワークプロキシ/パケット解析ツールを検知します。競技系ビルドで有効化する前に誤検知を確認してください。 |
| blockReverseEngineeringTools (Windows) | bool | false | ILSpy、dotPeek、Ghidra、WinDbg、IDA Pro などのリバースエンジニアリングツールを検知します。 |
| blockSystemMonitorTools (Windows) | bool | false | Process Explorer、Process Monitor、Process Hacker などのシステム監視ツールを検知します。パワーユーザーでの誤検知に注意してください。 |
| il2cppHashGameAssembly | bool | true | Windows IL2CPP ビルドで GameAssembly.dll をハッシュ化します。これは推奨される最小限の IL2CPP ファイルガードです。 |
| il2cppHashGlobalGameManagers | bool | true | globalgamemanagers を IL2CPP マニフェストの対象範囲に追加します。 |
| il2cppHashSharedAssets | bool | true | sharedassets* ファイルを IL2CPP の対象範囲に追加します。 |
| il2cppHashSceneFiles | bool | true | level* などの Unity シーンファイルを IL2CPP の対象範囲に追加します。 |
| il2cppHashResourcesAssets | bool | false | resources.assets を IL2CPP の対象範囲に追加します。Strict モードで有用ですが、まずパッチワークフローをテストしてください。 |
| il2cppAdditionalWatchedFiles | List<string> | — | プロジェクトがカスタムのネイティブペイロードを含む場合に、マニフェストのハッシュ化に含める追加の Windows IL2CPP 出力ファイルです。 |
| blockEmulator (Android) | bool | true | Android のみ。エミュレーターや未サポートのランタイム信号を整合性違反として扱います。QA/エミュレーターテスト中は緩め、本番ビルドではより厳格なポリシーを推奨します。 |
| blockSystemRwMount (Android) | bool | true | Android のみ。書き込み可能なシステムパーティションや root 相当のマウント状態を整合性違反として扱います。 |
| androidShaKeys | List<string> | — | 期待される APK 署名証明書の SHA-256 フィンガープリント一覧です。インストール済み APK がこのいずれかのキーで署名されていない場合は失敗します(Android のみ)。 |
| expectedBundleIds (iOS) | List<string> | — | 許可するiOS Bundle IDの一覧です。空の場合、この検査はスキップされます。 |
| excludedAssemblies | List<string> | — | ハッシュ検証時にスキップするアセンブリ名(.dll 拡張子なし)の一覧です。ランタイムで変化するアセンブリ(例: 生成コード)に使用します。 |
| checkIntegrityWithServer (Pro) | bool | false | ProサーバーAttestationを有効化します。クライアントがnonceを要求し、整合性証拠を送信して、ゲームサーバーまたは OZero Managed Verification で検証可能な署名済みOZAトークンを受け取ります。現在のサーバーでは、nonce が manifest hash、platform、SDK version、アプリ識別情報に紐づき、再利用や証拠差し替えを抑えます。 |
| enableManagedVerification (Pro) | bool | false | 自社バックエンドを持たないチーム向けの委任検証です。発行された OZA トークンを OZero が検証し、allow/warn/block verdict と短時間の managed session を返します。SDK は managed session の期限が切れる前に自動で再検証を試みます。checkIntegrityWithServer が必要です。 |
| requireManagedVerification (Pro) | bool | false | 有効にすると、Managed Verification のネットワーク失敗も検証失敗として扱います。通常は無効のままにし、一時障害時は Standard へ静かにダウングレードさせる運用を推奨します。 |
| attestRefreshLeadSeconds (Pro) | float | 300 s | クライアントが OZA トークンの期限切れより何秒前に更新を試みるかです。0 にすると期限前更新を無効にします。 |
| attestRefreshCooldownSeconds (Pro) | float | 30 s | attestation 更新の試行間に設ける最小のクールダウン時間です。 |
| manifestSigningPublicKey | string | — | requireManifestSignature が有効な場合に、マニフェスト署名の検証に使う RSA 公開鍵(PEM)です。 |
| requireManifestSignature | bool | false | 整合性マニフェスト自体が manifestSigningPublicKey で署名されているかを検証します。 |
| manifestSigningPrivateKeyPath | string | OZeroSigningKeys | ビルド時のマニフェスト署名に使う秘密鍵 PEM への、エディター専用のパスです。プレイヤービルドには含まれません。 |
Events
| Event | Description |
|---|---|
| OnValidationPassed | ローカル整合性チェックが違反なく完了したときに発生します。Pro サーバー attestation はまだ進行中の場合があります。 |
| OnAttestationPassed | Pro OZA attestation トークンが実際に発行された後にのみ発生します。ゲームサーバーログイン、PvP、ランキング、通貨フローは、このイベントまたは AttestationToken.IsValid(nowMillis) で検証し、通過した場合にのみ進めてください。 |
| OnValidationFailed | 整合性チェックが違反を検知したときに発生します。グローバルの onHackDetected イベントも ModulationType.BuildIntegrity とともにトリガーされます。 |
RSA 署名キーの生成(ビルド整合性)
Build Integrity を有効にし、Require Manifest Signature をオンにした場合、OZero は公開鍵署名(非対称署名)を用いて、整合性マニフェストが差し替えや改ざんを受けていないことを保証します。リリースビルドを作成する前に、Unity エディター内でキーペアを生成する必要があります。
ビルド時に OZero は秘密鍵でアセンブリマニフェストに署名し、その署名をビルドに埋め込みます。ランタイムでは、OZeroSecurityConfig に保存された公開鍵でその署名を検証します。署名が一致しない場合 — つまりマニフェストまたはバイナリが改変された場合 — ゲームはそれを改ざんとみなし、Response Settings に従って対応します。
キーペアの生成
- Unity エディターで、Project ウィンドウの
OZeroSecurityConfigを選択します。 - Inspector で Build Integrity セクションを展開します。
- Require Manifest Signature チェックボックスを有効にします。
- Generate Key Pair ボタンをクリックします。
- OZero が公開鍵署名のキーペアを生成します。公開鍵は
OZeroSecurityConfigに直接書き込まれます(Assets に保存)。秘密鍵は次の場所に保存されます:[ProjectRoot]/OZeroSigningKeys/manifest_private_key.pem - 確認ダイアログに秘密鍵の保存場所が表示されます。OK をクリックして閉じます。
- 秘密鍵ファイルは
Assets/フォルダーの外側に保存され、Unity がビルドに含めないようになっています。Assets/内に移動しないでください。 OZeroSigningKeys/をすぐに.gitignoreに追加してください。秘密鍵をバージョン管理にコミットすることは重大なセキュリティリスクです。- 秘密鍵を安全なオフラインの場所(暗号化 USB ドライブ、パスワードマネージャーなど)にバックアップしてください。このファイルを持つ者は、あなたのゲーム向けに正当なマニフェストを偽造できます。
- 秘密鍵を失った場合、新しいキーペアを生成する必要があります。新しい公開鍵は次のビルドに埋め込まれます。古い署名を持つ既出荷ビルドはすべてマニフェスト検証に失敗するため、差し替えが必要になります。
カスタム秘密鍵パス(CI/CD・チーム)
Manifest Signing Private Key Path フィールド(Inspector の Manifest Signing — Editor Only 配下に表示)で、秘密鍵の別の保存場所を指定できます。次の2つの場面で有用です:
- CI/CD パイプライン — 秘密鍵を CI シークレットとして保存し、ビルド時にそのパスを注入することで、ビルドマシンが鍵を永続的にディスク上へ持つ必要がなくなります。
- チーム環境 — 鍵を共有の安全なサーバーやシークレットマネージャーに保管し、マウントしたパスをフィールドに指定します。リリースビルドを実行するメンバーだけがアクセスできれば十分です。
既存キーペアの検証
ディスク上の秘密鍵が OZeroSecurityConfig に保存された公開鍵とまだ一致しているか不明な場合は、Validate Key Pair ボタンをクリックしてください。OZero が小さなテストペイロードに秘密鍵で署名し、公開鍵で検証します。一致すれば成功通知が表示されます。一致しない場合は、新しいペアを生成する必要があります。
- 秘密鍵を紛失または漏洩した。
- Validate Key Pair が不一致を報告した(鍵が同期していない)。
- 計画的なセキュリティポリシーの一環として意図的にキーをローテーションする。
再生成後、新しい公開鍵は次のビルドに自動で埋め込まれます。既出荷ビルドは新しい公開鍵ではマニフェスト検証に失敗するため、アップデートを配信する必要があります。
デュアル指紋によるキーローテーション(無停止)
Generate Key Pair ボタンは、公開鍵を同時に2か所へ保存します: OZeroSecurityConfig(Assets 内の ScriptableObject)の中、そして Assets/OZeroSDK/Scripts/Security/BuildIntegirity/OZeroManifestTrustAnchor.cs 内の SHA-256 フィンガープリント定数としてです。ランタイムでは SDK がまず、アセット内の公開鍵がアセンブリにピン留めされた指紋と一致するかを確認します — 一致しない場合、RSA 署名のチェック前にマニフェストが拒否されます。これにより、アセットと .sig ファイルの両方を攻撃者所有のキーに差し替える再パッカー攻撃を防ぎます。
OZeroManifestTrustAnchor.cs の中には2つの const スロットがあります: ExpectedPublicKeyFingerprintHex(現行の本番指紋)と PreviousPublicKeyFingerprintHex(任意の2つ目の指紋。定常状態では空)です。Matches() 検証器は、ライブの SPKI ハッシュがいずれかの値と等しければ true を返し、定数時間 XOR 比較を使用します。このデュアルスロット方式が、ホームページの「無停止キーローテーション」機能の基盤です。新しくビルドした SDK は、限定された猶予期間の間、新しいキー(Expected)と古いキー(Previous)の両方を信頼できるため、新リリースを配信する間も古い出荷ビルドは自分の古いマニフェストを検証し続けられます。
ローテーション手順(手動だが5分で完了)
- 現在の指紋を控える。
Assets/OZeroSDK/Scripts/Security/BuildIntegirity/OZeroManifestTrustAnchor.csを開き、ExpectedPublicKeyFingerprintHexの値をクリップボード(またはメモ用ファイル)にコピーします。 - previous スロットに移す。 同じファイルで、その値を
PreviousPublicKeyFingerprintHex(通常は"")に貼り付けます。保存します。 - 新しいキーペアを生成する。
OZeroSecurityConfigの Inspector で Generate Key Pair をクリックします。ダイアログが、これにより以前にベイクしたマニフェストが無効になる旨を警告するので Regenerate をクリックします。新しい秘密鍵が PEM ファイルに書き込まれ、新しい公開鍵がアセットの値を置き換え、新しい SHA-256 指紋がExpectedPublicKeyFingerprintHexに自動注入されます。手順2のPreviousPublicKeyFingerprintHexはそのまま残ります。 - 新しい SDK リリースをビルドして配信する — 通常のパッチ/ストアチャネル経由で。このビルドの新しいマニフェストは新しい秘密鍵で署名されます。
- フリートの切り替わりを待つ。 猶予期間の間、新しいビルドは両方のキーを信頼し、古いビルド(Expected として古い指紋のみをピン留め)は自分の古いマニフェストを検証し続けます。どちらの経路も壊れません。一般的な期間: ライブゲームで1〜4週間。
- previous スロットをクリアする。 テレメトリで古いビルドが0%になったことを確認したら、
PreviousPublicKeyFingerprintHex = ""に設定し、もう1度 SDK リリースを配信します。ローテーション完了です。
古い出荷バイナリには、すでに古いキーで署名された古いマニフェストと、Expected スロットとして古い指紋の埋め込みコピーが含まれています — 動作を続けるのに新しいキーを知る必要はありません。新しいビルドが Previous スロットを必要とするのは、プレイヤーが期間中に強制再インストールや旧バージョンへのロールバックを行った場合に、キャッシュされた古いマニフェストが引き続き検証できるようにするためだけです。古いビルドが現場から消えたら、次のリリースで Previous をクリアできます。
トラブルシュート
以下の5つの症状はすべて同じ防御スタックに由来します — ビルド時の PreBuild バリデーター(OZeroBuildPreflightValidator)、起動時のアンカーガード(OZeroManifestTrustAnchor.ValidateConfigurationOrFail)、ランタイム検証器(OZeroBuildIntegrityValidator.VerifyManifestSignature)です。いずれの場合も対処は、3つの成果物(秘密鍵 PEM、OZeroSecurityConfig 内の公開鍵、OZeroManifestTrustAnchor 内の指紋)を再び同期させることです。
ExpectedPublicKeyFingerprintHex が空文字列です。Editor および Development ビルドは警告付きで許容しますが、リリースビルドは信頼されないマニフェストを受け入れる前に起動時にフェイルファストします。対処: エディターで Generate Key Pair を1度実行してください — 指紋が const に自動注入されます。const がすでに埋まっているのにビルドが abort する場合は、アセンブリハッシュブロブ(oz_ahash.bin)が古い可能性があります — クリーンな状態から再ビルドしてください。
PreBuild バリデーター(callbackOrder 51)が OZeroSecurityConfig.Integrity.ManifestSigningPublicKey が空であることを検出しました。対処: Inspector で OZeroSecurityConfig を開き → Build Integrity を展開 → Generate Key Pair をクリックして再ビルドします。注: このチェックは Android / iOS(OS レベル署名)と IL2CPP Standalone(署名対象の個別 DLL ファイルがない)ではスキップされるため、キー欠落が止めるのは Mono Standalone ターゲットのみです。
OZeroSecurityConfig の公開鍵文字列のハッシュが、ExpectedPublicKeyFingerprintHex にも PreviousPublicKeyFingerprintHex にも一致しません。正当にビルドされたバイナリでは、手動編集で2つの成果物が同期しなくなった後に起こります。対処: エディターで Tools → OZero → Validate Manifest Signing Keys を実行してください — キーペアが整合していればツールが const を自動で書き直します。不一致を報告する場合は Generate Key Pair でペアを再生成してください。改ざんされたバイナリでは、このメッセージは意図したフェイルクローズ信号です — APK / .exe が再パッケージされていないか調査してください。
ローテーション手順の手順2を忘れています。新しい SDK リリースが PreviousPublicKeyFingerprintHex = "" で出荷されたため、古いビルドをキャッシュ済みで強制再起動したプレイヤーは新しいキーで署名されたマニフェスト(古いビルドが信頼しない)に遭遇します — あるいはさらに悪いことに、強制再インストールで新しくキャッシュされた古いマニフェストが取得され、PEM がローテーション済みのため古いビルドの trust anchor で検証できません。対処: PreviousPublicKeyFingerprintHex に古い指紋を設定したホットフィックス SDK リリースを配信してください。次のマニフェスト取得は、いずれのキーでも検証されます。
CI マシンには OZeroSigningKeys/manifest_private_key.pem がディスク上に存在しません。.gitignore によって正しく除外されているためです。対処: PEM を CI シークレット(GitHub Actions Secret、GitLab Variable、Jenkins Credentials など)として保存し、Unity ビルドステップの前にパイプラインがワークスペースの OZeroSigningKeys/manifest_private_key.pem へ書き出すようにしてください。あるいは OZeroSecurityConfig の Manifest Signing Private Key Path を CI ランナーがマウントできるパス(例: シークレットマネージャーのマウント)に設定します。すべての CI ランナーが同じ PEM を使うようにしてください — 異なる PEM は、公開鍵が一致していても異なる署名を生成します。
インストール元設定
承認されたストアまたは経路からインストールされた場合のみゲームを実行できるよう制限します。サイドロードや再パッケージされた APK の防止に有効です。
| フィールド | Type | 既定値 | 説明 |
|---|---|---|---|
| Activate Install Source | bool | true | Install Source モジュールを有効化します。 |
| allowGooglePlayStore | bool | true | Google Play ストア経由のインストールを許可します。 |
| allowSamsungGalaxyStore | bool | false | Samsung Galaxy Store 経由のインストールを許可します。 |
| allowAmazonAppstore | bool | false | Amazon Appstore 経由のインストールを許可します。 |
| allowHuaweiAppGallery | bool | false | Huawei AppGallery 経由のインストールを許可します。 |
| allowOneStore | bool | false | ONE Store(韓国)経由のインストールを許可します。 |
| allowXiaomiGetApps | bool | false | Xiaomi GetApps 経由のインストールを許可します。 |
| allowOppoAppMarket | bool | false | OPPO App Market 経由のインストールを許可します。 |
| allowVivoAppStore | bool | false | Vivo App Store 経由のインストールを許可します。 |
| allowADB | bool | false | ADB(Android Debug Bridge)経由のインストールを許可します。内部テスト用途でのみ有効にしてください。 |
| allowDetectionFailed | bool | false | Androidのinstaller package照会やJNI呼び出しが失敗した場合でも実行を許可します。リリースビルドでは無効化を推奨します。 |
| allowUnknownSources | bool | false | 組み込みまたはカスタム許可リストにないインストール元を許可します。地域ストア対応など、検証済みの場合のみ使用してください。 |
| enableServerSync (Pro) | bool | false | 検知したインストーラーパッケージを OZero サーバーへ送信し、許可リスト検証と監査を行います。Pro のみ。 |
| customAuthorizedPackages | List<string> | — | 追加で許可するインストーラーのパッケージ名(例: com.yourcompany.launcher)です。 |
| reportViolationToCallback | bool | true | 許可されていないインストール元が検知された場合に、サーバーへレポートを送信します。 |
| logRawInstallerPackage | bool | true | 元のインストーラーパッケージ名をコンソールにログ出力します。カスタムストアの正しいパッケージ名を特定する開発段階で有用です。 |
Steam Anti-Piracy設定
Steamで配布するPCビルドについて、Steam起動経路、App ID、権限状態、リリース設定を確認します。Standardはローカル検証であり、Steamサーバー証拠によるより強い所有権検証はProのServer Steam Attestationで提供します。
| フィールド | Type | 既定値 | 説明 |
|---|---|---|---|
| Activate Steam Anti-Piracy | checkbox | Off | Steam Anti-Piracyの有効化チェックボックスです。Steam App IDと配布フローはプロジェクトごとに異なるため、初期値はOffです。まずobserve/QAモードで状態を確認し、その後リリースビルドのポリシーを強めてください。 |
| expectedSteamAppId | int | 0 | プロジェクトのSteam App IDです。ローカル確認で開発用AppID 480を使った場合は、リリース前に実際のApp IDへ置き換えてください。 |
| requireSteamLaunch | bool | true | ゲームが実行ファイルの直接起動ではなくSteam経由で起動されたかを確認します。開発時の直接起動テストとリリースポリシーは分けて扱ってください。 |
| requireSteamApiInit | bool | true | Steam APIの初期化が成功するかを確認します。ローカル開発起動ではSteamworks設定により失敗することがあるため、最終判断は実際のSteam配布経路で確認してください。 |
| requireSubscribedCurrentApp | bool | true | 現在のSteamアカウントがアプリを所有または利用権を持つかを確認します。これはローカル検証であり、サーバー側の所有権検証はProで扱います。 |
| requiredDlcAppIds | List<int> | — | 保護対象の DLC フローで所有が必要な、任意の DLC App ID です。 |
| blockSteamAppIdTxtInRelease | bool | true | 開発用の steam_appid.txt ファイルが残っているリリースビルドを失敗扱いにします。このファイルはローカル開発確認用であり、配布物には含めないでください。 |
| validateSteamApiDllHash | bool | false | 任意で、Steam API DLL のハッシュを既知の正常な SHA-256 値と照合して検証します。 |
| allowFamilySharing / allowFreeWeekend / allowTimedTrial | bool | true | Steam のファミリーシェア、フリーウィークエンド、期間限定トライアルの利用権状態を受け入れるかどうかを制御します。 |
| enableServerSteamAttestation (Pro) | bool | false | Pro専用です。ローカルクライアント結果より強いサーバー側所有権検証のため、Steamの利用権証拠をOZeroサーバーへ送信します。 |
デバイスバインディング設定
ハードウェア指紋を使ってゲームアカウントを最初のデバイスに紐付けます。別のハードウェアへのアカウント移行を検知します。
商用運用での目的
デバイスバインディングはProの運用レイヤーとして特に有効です。ライセンスをサーバー登録済みのハードウェア指紋に紐付けることで、リスクのあるデバイスの隔離、カジュアルなライセンス共有の抑制、正当なデバイス変更のサポートを、ライセンス全体を停止せずに行えます。
繰り返しリスクのあるデバイスをブロック
SpeedHack、Injection、Install Source、Build Integrityなどのセキュリティイベント証拠を確認したうえで使用します。ブロックされたデバイスは次回のアクティベーション、登録、検証(verify)、ポリシー(policy)チェックで DEVICE_BLOCKED を受け取ります。
正当なユーザーをリセット
端末交換、OS再インストール、ハードウェア交換、通常の指紋不一致にはReset Tokenを使用します。トークンは5分間有効、1回限りで、正確なライセンスとデバイスに紐付けられます。
デバイススロットを制御
Proライセンスでは maxDevices により登録可能なアクティブなサーバー指紋数を制限します。ブロック済み指紋は再利用可能な信頼スロットではないため、リセットまたは削除はサポート確認後に使用してください。
Reset Tokenサポートフロー
- 通常のサポート手順でプレイヤーアカウントとリセット理由を確認します。
- Customer Portal → Device Bindingを開き、対象デバイスを見つけてReset Tokenを発行します。
- トークンは認証済みのサポートチャネルでのみ送信します。長期間残る公開チャットやスクリーンショットには保存しないでください。
- ゲームまたはサポートUIはトークンを
OZeroDeviceBindingDetector.Instance?.ClearStoredFingerprint(token.Trim())に渡します。 - SDKがトークンを消費した後、アプリを再起動するか保護された起動フローに再度入ると、現在のハードウェア指紋が再登録されます。
| フィールド | Type | 既定値 | 説明 |
|---|---|---|---|
| Activate Device Binding | bool | true | Device Binding モジュールを有効化します。 |
| hardwareChangeTolerance | int (0–3) | 1 | 違反をトリガーするまでに許容するハードウェア構成要素の変更回数です。0 = 厳格(変更不可)、3 = 寛容(主要ハードウェアの交換)。1 は軽微な OS またはファームウェア更新を許容する水準です。 |
| storageKey | string | "ozero_dfp" | 暗号化されたデバイス指紋を保存する PlayerPrefs キーです。ゲーム内の既存キーと衝突する場合のみ変更してください。 |
| enableServerSync | bool | false | サーバー側検証のために、デバイス指紋をバックエンドサーバーと同期します。 |
| maxDevices (Pro) | int | 0 | 想定するサーバー側デバイス上限を示す値です。実際の上限はサーバーのライセンス記録で強制されるため、このローカル値だけを変更しても本番上限は増えません。 |
スピードハック設定
Unity の Time.realtimeSinceStartup を、ネイティブプラットフォームのタイマーや、任意で信頼できるウェブ時間ソースと比較して、タイムスケール操作(スピードハック)を検知します。
| フィールド | Type | 既定値 | 説明 |
|---|---|---|---|
| Activate Speed & Time Hack | bool | true | Speed Hack Detector モジュールを有効化します。 |
| autoStart | bool | true | ゲーム起動時に自動で検知を開始します。無効にした場合は OZeroSpeedHackDetector.StartDetection() で手動開始する必要があります。 |
| checkInterval | float | 1.0 s | 検出器がタイマーをサンプリングして比較する間隔(秒)です。 |
| requiredDetections | int | 3 | 違反がトリガーされるまでに必要な連続異常サンプル数です。不安定なデバイスでの誤検知を減らすには値を大きくしてください。 |
| ratioTolerance | float | 0.15 | サンプルを異常とみなす前の、Unity 時間とネイティブタイマー間の許容偏差(±15%)です。 |
| maxAllowedRatio | float | 4.0 | 許容される最大の時間比率です。この値を超える比率は、requiredDetections に関係なく即座にスピードハックと判定されます。 |
| detectSlowHack | bool | true | 速度を上げるツールだけでなく、時間を遅くするツール(許容差を引いた 1.0 未満の比率)も検知します。 |
| enableTimeScaleDetection | bool | true | メモリエディターなどによってプログラム的に設定された異常な Time.timeScale 値を検知します。 |
| hackDetectMultiplier | float | 1.3 | maxAllowedRatio × hackDetectMultiplier を超えるサンプルは、requiredDetections に達する前でも検知として集計されます。 |
| enableThreadTimerCheck | bool | true | バックグラウンドスレッドのタイマーを追加の基準クロックとして使用し、メインスレッドのみに影響するハックをより困難にします。 |
| useWebTimeValidation | bool | false | webTimeUrl から定期的に現在時刻を取得してデバイス時計と比較し、デバイスレベルの時間操作を検知します。 |
| webTimeUrl | string | — | 信頼できる時刻 API エンドポイントの URL(Unix タイムスタンプまたは RFC 2616 Date ヘッダーを返す必要があります)です。useWebTimeValidation 有効時に必須です。 |
| webSyncInterval | float | 15 s | ウェブ時刻サーバーと同期する間隔(秒)です。 |
| webRatioTolerance | float | 0.15 | デバイス時刻とウェブサーバー時刻間の許容偏差(±15%)です。 |
| timeOffsetTolerance | float | 60 s | 違反をトリガーする前に許容される、デバイスとウェブサーバー間の絶対時計オフセット(秒)です。 |
| focusIgnoreTime | float | 4 s | アプリがフォーカスを取り戻した直後に無視する秒数です(例: マルチタスクからの復帰)。OS がアプリを一時停止した際の誤検知を防ぎます。 |
| loadingGraceTime | float | 6 s | 起動時に検知結果を無視する猶予時間(秒)です。シーン読み込み中の誤検知を防ぎます。 |
| lagSpikeIgnore | float | 0.5 s | フレームのデルタがこの値を超えるサンプルは破棄されます(時間操作ではなく、実際のラグスパイクとみなされます)。 |
| buildFailIfTimeScaleTampered | bool | true | 保護対象コードが設定ポリシーの範囲外で Time.timeScale を変更しているように見える場合に、検証を失敗させるビルド時ガードです。 |
| timeScaleTamperExemptions | List<string> | — | ポーズやバレットタイムのシステムなど、意図的に Time.timeScale を変更してよいクラスまたはメソッドのパターンです。 |
| webTimeUrls | string[] | — | 任意の複数の信頼できる時刻エンドポイントです。検出器は、ウェブ時刻を信頼する前に複数のエンドポイントの成功を要求できます。 |
| minSuccessfulEndpoints | int | 2 | 複数のエンドポイントを設定した場合に、成功応答が必要な最小のウェブ時刻エンドポイント数です。 |
| maxConsecutiveFailures | int | 6 | 利用不可ポリシーを適用する前に許容する、連続したウェブ時刻失敗の回数です。 |
| onWebTimeUnavailable | enum | WarnOnly | 信頼できるウェブ時刻に到達できない場合に使うポリシーです。ネットワーク条件をテストしてから、より厳格なモードを選んでください。 |
| detectTimeHack | bool | true | 速度比率チェックに加えて、デバイス時計とウェブ時刻の操作チェックを有効化します。 |
| webSyncJitterPercent | float | 20% | 予測可能なポーリングを避けるため、ウェブ時刻の同期間隔をランダム化します。 |
| sustainedLagThreshold | float | 0.15 | 繰り返される遅いフレームを、チートの証拠ではなく持続的なラグとして扱うためのしきい値です。 |
| sustainedLagGraceDuration | float | 3 s | 持続的なラグを分類している間に適用する猶予時間です。 |
| overloadStrictMultiplier | int | 3 | 異常なタイミング状態が繰り返された後、過負荷処理をより厳格にするための乗数です。 |
| enableRemoteSpeedHackConfig (Pro) | bool | false | クライアントコードを変更せずに、Pro サーバーポリシーで選択した Speed & Time Hack のしきい値を上書きできるようにします。 |
| remoteSpeedHackConfigInterval | float | 300 s | リモートの Speed & Time Hack 設定を更新する頻度です。 |
| enableSignedServerTime (Pro) | bool | false | 利用可能な場合に署名済みのサーバー時刻を使用し、署名のない応答で時刻検証がなりすまされないようにします。 |
Physics Hack Detector
OZeroPhysicsHackDetector は、各プレイヤーオブジェクトごとに独立した検知しきい値が必要なマルチプレイヤー/MMORPG 向けに設計されています。プレイヤープレハブに直接コンポーネントを追加し、Inspector でオブジェクトごとに設定を構成してください。スポーンロジックで Initialize(playerId) を呼び出して検知を有効化します。| フィールド | Type | 既定値 | 説明 |
|---|---|---|---|
| maxAllowedSpeed | float | 15 u/s | 許容される最大移動速度(Unity 単位/秒)です。ゲームで許容される最大の正当なプレイヤー速度に合わせて調整してください。 |
| distanceTolerance | float | 2.0 u | ネットワーク遅延や物理の不正確さを補正するための追加距離許容値です。 |
| obstacleLayer | LayerMask | — | 壁や障害物を表すレイヤーマスクです。linecast によるウォールクリップ検知に使用されます。 |
| checkInterval | float | 0.05 s | 物理検証器がプレイヤーの位置と速度をサンプリングする間隔(秒)です。 |
| maxDeltaTimeCap | float | 0.1 s | 距離計算に使うデルタ時間の上限です。ラグスパイクによってテレポート検知が隠れるのを防ぎます。 |
インジェクション設定
アセンブリインジェクション、DLL ハイジャック、IL2CPP パッチなどの不正なコードインジェクションを検知します。
| フィールド | Type | 既定値 | 説明 |
|---|---|---|---|
| Activate Injection & Hooking | checkbox | On | Code Injection Detector モジュールを有効化します。検知ロジックは完全に Native C++ レイヤーで動作し、追加設定は不要です。 |
| enableServerWhitelist (Pro) | bool | false | サーバーから信頼できるネイティブモジュールのポリシーをダウンロードし、承認済みのオーバーレイやパートナーモジュールを集中管理で許可できるようにします。 |
| serverWhitelistRefreshInterval | float | 0 s | サーバー管理の許可リストポリシーの更新間隔です。0 は起動時またはポリシーのブートストラップ時のみ更新する意味です。 |
| requireSignerForNativeWhitelist | bool | false | ネイティブ許可リストの項目に、ファイルハッシュだけでなく署名者の識別情報も含めることを要求します。より強力ですが、クリーンなモジュール署名者データが必要です。 |
| enableRemoteInjectionConfig (Pro) | bool | true | クライアントコードを変更せずに、Pro サーバーポリシーで Injection のしきい値やプローブを調整できるようにします。 |
| remoteInjectionConfigInterval | float | 300 s | リモートの Injection ポリシーを更新する頻度です。 |
| enableWindowsModuleIdentityScan | bool | true | 読み込まれた Windows ネイティブモジュールをスキャンし、ハッシュ/署名者の識別情報を信頼ポリシーと照合します。 |
| scanIntervalSeconds | float | 1 s | インジェクションプローブの基本となるランタイムスキャン間隔です。 |
| windowsModuleIdentityScanIntervalSeconds | float | 5 s | より負荷の高い Windows モジュール識別スキャンの、個別の間隔です。 |
| scanJitterPercent | float | 20% | プローブを予測しにくくするため、スキャンのタイミングにランダムなジッターを加えます。 |
| enableExecutablePrivateMemoryScan | bool | true | インジェクトされたシェルコードやランタイムパッチャーがよく使う、実行可能なプライベートメモリ領域を検知します。 |
| enableInlineHookScan | bool | false | 既知のコードエントリポイントにおける不審なインラインパッチを検知します。Strict モードは互換性テストの後にこれを有効化します。 |
| enableThreadStartAddressScan | bool | true | スレッドの開始アドレスが、信頼できるモジュールの外側の不審な場所にないかを確認します。 |
| enableExternalProcessHandleScan | bool | true | ゲームプロセスに対して不審なハンドルを保持する外部プロセスを検知します。 |
| detectionConfidenceThreshold | int | 70 | 複合的なインジェクション信号を違反として扱う前に必要な、最小の信頼度スコアです。 |
| enableWebRuntimeTamperScan (WebGL) | bool | true | WebGL専用の軽量ブラウザー改ざん検査です。Native C++保護ではないため、限定的なクライアント信号として扱ってください。 |
| WebGL probes | bools | true | WebGL ビルド向けに、DevTools、クロックフック、ネットワークフック、WASM フック、ストレージフック、暗号フックのチェックを制御します。 |
PlayerPrefs の暗号化
Unity の PlayerPrefs に保存されるデータ(設定、ユーザー環境設定など)を保護するには、PlayerPrefs を OZeroSafePlayerPrefs に置き換えてください。API は同一です。
using OZeroSDK.Security;
// Save a value
OZeroSafePlayerPrefs.SetInt("score", 4200);
OZeroSafePlayerPrefs.SetFloat("volume", 0.8f);
OZeroSafePlayerPrefs.SetString("username", "Hero");
// Read a value
int score = OZeroSafePlayerPrefs.GetInt("score", 0);
float volume = OZeroSafePlayerPrefs.GetFloat("volume", 1.0f);
string username = OZeroSafePlayerPrefs.GetString("username", "");
セーブファイルの暗号化
セーブファイルを暗号化するには、File.ReadAllText / File.WriteAllText の代わりに OZeroSV_File を使用してください。ファイルは書き込み時に自動で暗号化され、読み込み時に復号されます。読み込み時には改ざんも検知します。
using OZeroSDK.Security;
string path = Application.persistentDataPath + "/save.json";
// Write encrypted file
OZeroSV_File.WriteAllText(path, jsonString);
// Read and decrypt file
string json = OZeroSV_File.ReadAllText(path);
developerSecret を変更しないでください。developerSecret は OZeroSafePlayerPrefs と OZeroSV_File のデータを保護する基準値の 1 つです。リリース後にこの値を変更すると、以前のバージョンで保存した保護データを開けなくなる可能性があります。
4
インゲーム変数の保護(Secure Types)
Secure Types は、通常の C# 変数型を暗号化された型に置き換えます。値は Native C++ ヒープに格納されるため、Cheat Engine のようなツールでメモリをスキャンしても見つけられません。置き換えは型名を変えるだけで、15 種類の型に対応しており、一般的な数値型すべて、bool、string、Vector2、Vector3、バイト配列をカバーします。すべての演算子と暗黙的変換も同じように動作します。
対応する型
| 変更前 | 変更後(OZero) |
|---|---|
| int | OZeroSV_Int |
| long | OZeroSV_Int64 |
| uint | OZeroSV_UInt |
| ulong | OZeroSV_UInt64 |
| short | OZeroSV_Short |
| ushort | OZeroSV_UShort |
| byte | OZeroSV_Byte |
| float | OZeroSV_Float |
| double | OZeroSV_Double |
| decimal | OZeroSV_Decimal |
| bool | OZeroSV_Bool |
| string | OZeroSV_String |
| Vector2 | OZeroSV_Vector2 |
| Vector3 | OZeroSV_Vector3 |
| byte[] | OZeroSV_Buffer |
サンプルコード
// ── Before: plain C# variable ──────────────────────────────
using UnityEngine;
public class PlayerStats : MonoBehaviour
{
public int gold = 0;
public float speed = 5.0f;
public int hp = 100;
}
// ── After: OZero Secure Types (only the type name changes) ──
using UnityEngine;
using OZeroSDK.Security;
public class PlayerStats : MonoBehaviour
{
public OZeroSV_Int gold = 0;
public OZeroSV_Float speed = 5.0f;
public OZeroSV_Int hp = 100;
// All arithmetic works exactly as before — no code changes needed
void TakeDamage(int dmg) => hp -= dmg;
void AddGold(int amount) => gold += amount;
}
7
セキュリティイベントの処理(任意)
デフォルトでは、OZero は設定された応答ポリシーに従ってアプリを終了するかログのみを残します。独自の警告画面、サーバーログ送信、終了前の保存処理が必要な場合はコールバックを登録できます。コールバックは OZeroSecurityEvent として、変調タイプ、abort code、メッセージキー、詳細メッセージ、終了予定かどうかを渡します。
using UnityEngine;
using OZeroSDK.Security;
public class SecurityHandler : MonoBehaviour
{
void OnEnable()
{
// RegisterUserCallback runs on the user chain only.
// The built-in default handler runs independently and cannot be silenced.
OZeroSecurityManager.Instance.RegisterUserCallback(OnThreatDetected);
}
void OnDisable()
{
OZeroSecurityManager.Instance.UnregisterUserCallback(OnThreatDetected);
}
void OnThreatDetected(OZeroSecurityEvent evt)
{
// evt contains Type, AbortCode, AbortCodeHex, MessageKey, Message, and WillAbort.
Debug.LogWarning(
$"OZero threat: {evt.Type} {evt.AbortCodeHex} {evt.Message}");
switch (evt.Type)
{
case ModulationType.SpeedHack:
// e.g. kick the player, show warning, report to server
break;
case ModulationType.BuildIntegrity:
// evt.WillAbort is usually true for fatal build integrity violations.
break;
case ModulationType.Injection:
break;
}
if (evt.WillAbort)
{
// Last chance to flush your own analytics or save state.
}
}
}
OZeroSecurityEvent、ModulationType、OZeroAbortCode の全リファレンスは API Reference に記載されています。
evt.WillAbort が true の場合、現在の応答ポリシーではコールバック後にアプリが終了します。独自 analytics flush や保存処理は短時間で終えてください。
違反は次の4つに分岐します: (1) OZeroSecurityManager.BuiltinResponse — 常に実行される既定ハンドラー、(2) あなたの OZeroSecurityReceiver.HandleModulation オーバーライドと Inspector の onHackDetected イベント — 任意のシーンレベルフック、(3) OZeroInternalFallbackReceiver — Response.ForceQuitOnDetection を読み取り、シーンにレシーバーがなくても強制適用、(4) ネイティブ側の OZ_ReportViolation — 管理パッチ面を完全に迂回する任意の C++ エクスポート。いずれか1つの経路をパッチまたはスタブ化しても、もはや SDK を無力化できません。
次のステップ
これでコアの OZero 保護が動作しています。各クラス、メソッド、設定オプションの詳細は、API リファレンス全体をご覧ください。