Tauriの基礎 - セキュリティモデル

提供: MochiuWiki : SUSE, EC, PCB

📢 Webサイト閉鎖と移転のお知らせ
このWebサイトは2026年9月に閉鎖いたします。
新しい記事は移転先で追加しております。(旧サイトでは記事を追加しておりません)

概要

Tauriのセキュリティモデルは、デスクトップアプリケーションにおける堅牢なセキュリティ基盤を提供するために設計された多層防御システムである。
従来のElectron等のフレームワークとは異なり、TauriはRustバックエンドとWebViewフロントエンドの間に明確なTrust Boundary (信頼境界) を設け、全ての通信を厳格に制御する。

Tauri v2では、従来のallowlistシステムを一新し、Permissions (権限)、Capabilities (能力)、Scopes (スコープ) からなる3層のアクセス制御システムを導入した。
このシステムにより、開発者は各ウインドウ、各コマンド、各パラメータに対してきめ細かいアクセス制御を設定できる。
また、リモートコードからのアクセスを制御する機能も備えており、信頼できるドメインのみに特定の権限を付与することが可能である。

セキュリティモデルを正しく理解し設定することは、ユーザーのデータを保護し、脆弱性を防ぐために不可欠である。


Trust Boundaryモデル

信頼境界の概念

Trust Boundary (信頼境界) は、異なる信頼レベルを持つコンポーネント間の境界を定義するセキュリティ概念である。

下表に、Tauriアプリケーションにおける主要な信頼境界を示す。

Tauriのセキュリティレイヤー
レイヤー 説明
Rust Core (信頼済み) フルアクセス権限を持つ
ファイルシステム、OS API、ネットワークへの直接アクセス
開発者が完全に制御
WebView Frontend (低信頼) 制限付きアクセス
IPCを通じた間接的なみアクセス
外部コンテンツの読み込み可能性
IPC Layer (境界保護) Rust CoreとWebView間の通信を仲介
全てのデータを検証・フィルタリング


境界違反の防止

信頼境界を適切に管理しない場合、以下に示す脆弱性が発生する可能性がある。

  • 権限昇格
    低信頼コードが高信頼リソースにアクセス
  • データ漏洩
    機密データが保護されていない領域に流出
  • コードインジェクション
    外部コードがアプリケーションロジックに侵入


IPCレイヤーの役割

 // IPCレイヤーは自動的に以下を検証
 // 1. 呼び出し元の権限
 // 2. パラメータの妥当性
 // 3. スコープ内のリソースアクセス
 
 #[tauri::command]
 // IPCレイヤーがこのコマンドへのアクセスを制御
 fn read_sensitive_file(path: String) -> Result<String, String> {
    // Rust Core内で実行 (信頼済み)
    std::fs::read_to_string(&path)
       .map_err(|e| e.to_string())
 }



Permissions (コマンドの権限定義)

Permissionsの基本

Permissionsは、Tauriコマンドへのアクセスを制御するON / OFFトグルである。

Permissionsの動作
動作 説明
許可 コマンドの実行を許可
拒否 コマンドの実行を拒否
デフォルト 許可されていないコマンドは自動的に拒否


Built-in Permissions

Tauriは、コア機能とプラグインに対して定義済みのパーミッションを提供する。

 // src-tauri/capabilities/default.json
 {
   "identifier": "default",
   "description": "Default capability for the main window",
   "windows": ["main"],
   "permissions": [
     // コアパーミッション
     "core:default",
     "core:app:default",
     "core:window:default",
 
     // シェルパーミッション
     "shell:allow-open",
     "shell:allow-execute",
 
     // ファイルシステムパーミッション
     "fs:default",
     "fs:allow-read-text-file",
     "fs:allow-write-text-file",
 
     // ダイアログパーミッション
     "dialog:default",
     "dialog:allow-open",
     "dialog:allow-save"
   ]
 }


カスタムパーミッションの定義

独自のコマンドに対してカスタムパーミッションを定義する。

 // src-tauri/capabilities/my-app.json
 {
   "identifier": "my-app-permissions",
   "description": "Custom permissions for my app",
   "windows": ["main"],
   "permissions": [
     // カスタムコマンドのパーミッション
     {
       "identifier": "my-app:allow-get-user-data",
       "allow": []
     },
     {
       "identifier": "my-app:allow-update-settings",
       "allow": []
     }
   ]
 }


パーミッションファイルの構造

パーミッションは、src-tauri/permissions/ ディレクトリに定義する。

 # src-tauri/permissions/my-app.toml
 
 # グループ定義
 [default]
 description = "Default permissions for my app"
 
 # 許可パーミッション
 [[default.permissions]]
 identifier = "allow-get-user"
 description = "Allow getting user data"
 
 [[default.permissions]]
 identifier = "allow-update-user"
 description = "Allow updating user data"
 commands = ["get_user", "update_user"]


パーミッションの拒否

特定のパーミッションを明示的に拒否することも可能である。

 {
   "permissions": [
     // 読み取りは許可
     "fs:allow-read-text-file",
     // 書き込みは明示的に拒否
     {
       "identifier": "fs:deny-write-text-file",
       "deny": []
     }
   ]
 }



Capabilities (ウインドウごとの権限セット)

Capabilitiesの基本

Capabilitiesは、特定のウインドウ または WebViewにパーミッションとスコープを割り当てる設定である。

  • ウインドウ単位での権限管理
    各ウインドウに異なる権限セットを割り当て可能
  • プラットフォーム固有の設定
    Windows、MacOS、Linuxで異なる権限を設定可能
  • 複数ウインドウの一括設定
    複数のウインドウに同じ権限を適用


Capabilities ファイルの構造

 // src-tauri/capabilities/default.json
 {
   "$schema": "../gen/schemas/desktop-schema.json",
   "identifier": "default",
   "description": "Default capability for main window",
   "windows": ["main"],
   "permissions": [
     "core:default",
     "shell:allow-open",
     "dialog:default"
   ],
   "platforms": ["linux", "MacOS", "windows"]
 }


複数ウインドウのCapabilities

 // src-tauri/capabilities/main-window.json
 {
   "identifier": "main-window",
   "description": "Main application window",
   "windows": ["main"],
   "permissions": [
     "core:default",
     "fs:default",
     "shell:allow-open",
     "dialog:default"
   ]
 }


 // src-tauri/capabilities/settings-window.json
 {
   "identifier": "settings-window",
   "description": "Settings window - limited permissions",
   "windows": ["settings"],
   "permissions": [
     "core:default",
     // 設定ウインドウはファイルシステムアクセス不要
     "dialog:allow-message"
   ]
 }


 // src-tauri/capabilities/viewer-window.json
 {
   "identifier": "viewer-window",
   "description": "Document viewer - read-only access",
   "windows": ["viewer-*"],  // ワイルドカードで複数ウインドウに適用
   "permissions": [
     "core:default",
     "fs:allow-read-text-file",
     // 書き込みパーミッションは付与しない
   ]
 }


プラットフォーム別Capabilities

 {
   "identifier": "platform-specific",
   "description": "Platform-specific permissions",
   "windows": ["main"],
   "permissions": [
     "core:default"
   ],
   "platforms": {
     "MacOS": {
       "permissions": [
         "core:default",
         // MacOS固有のパーミッション
       ]
     },
     "windows": {
       "permissions": [
         "core:default",
         // Windows固有のパーミッション
       ]
     },
     "linux": {
       "permissions": [
         "core:default",
         // Linux固有のパーミッション
       ]
     }
   }
 }



スコープによるアクセス制限

スコープの基本概念

Scopesは、コマンドのパラメータを検証し、アクセス可能なリソースを制限する。

スコープの構成要素
要素 説明
Allow Scope 許可された値 / パターンのリスト
Deny Scope 拒否された値 / パターンのリスト
パターンマッチング ワイルドカードや正規表現で柔軟に制御


ファイルシステムスコープ

 {
   "identifier": "fs:allow-read-text-file",
   "allow": [
     // アプリデータディレクトリ配下のみ許可
     { "path": "$APPDATA/**" },
     // リソースディレクトリ配下のみ許可
     { "path": "$RESOURCE/**" },
     // 特定のファイルのみ許可
     { "path": "/home/user/documents/allowed.txt" }
   ],
   "deny": [
     // 機密ファイルは明示的に拒否
     { "path": "$APPDATA/**/secrets.json" },
     { "path": "/etc/passwd" }
   ]
 }


HTTPスコープ

 {
   "identifier": "http:default",
   "allow": [
     // 特定のドメインのみ許可
     { "url": "https://api.example.com/**" },
     { "url": "https://cdn.example.com/**" }
   ],
   "deny": [
     // プライベートネットワークへのアクセスを拒否
     { "url": "http://localhost/**" },
     { "url": "http://192.168.*.*/**" },
     { "url": "http://10.*.*.* /**" }
   ]
 }


シェルスコープ

 {
   "identifier": "shell:allow-execute",
   "allow": [
     // 特定のコマンドのみ許可
     {
       "name": "git",
       "args": ["status", "log", "diff"]
     },
     {
       "name": "npm",
       "args": ["install", "run"]
     }
   ],
   "deny": [
     // 危険なコマンドを拒否
     {
       "name": "rm",
       "args": ["-rf", "/"]
     }
   ]
 }


スコープの優先順位

スコープの評価順序
順序 評価内容 説明
1 Denyスコープをチェック 拒否リストにマッチした場合、即座に拒否
2 Allowスコープをチェック 許可リストにマッチした場合、許可
3 デフォルト拒否 どちらにもマッチしない場合、拒否



リモートコードのアクセス制御

リモートIPCアクセスの概要

デフォルトでは、Tauri APIはバンドルされた処理 (アプリケーションに含まれるソースコード) からのみアクセス可能である。

リモートソース (外部Webサーバ) からのアクセスを許可するには、明示的な設定が必要である。

dangerousRemoteUrlIpcAccess 設定

信頼できるドメインに対して、特定の権限を付与する。

 // src-tauri/tauri.conf.json
 {
   "security": {
     "dangerousRemoteUrlIpcAccess": [
       {
         "windows": ["main"],
         "domain": "trusted.example.com",
         "plugins": ["my-plugin"],
         "enableTauriAPI": false
       },
       {
         "windows": ["webview"],
         "domain": "app.example.com",
         "plugins": ["http", "fs"],
         "enableTauriAPI": true
       }
     ]
   }
 }


設定パラメータの説明

dangerousRemoteUrlIpcAccessパラメータ
パラメータ 説明
windows string[] アクセスを許可するウインドウラベル
domain string 信頼するドメイン
plugins string[] アクセスを許可するプラグイン
enableTauriAPI boolean TauriコアAPIへのアクセスを許可



セキュリティ上の注意点

リモートアクセスを許可する場合の重要な考慮事項を以下に示す。

  • 完全に信頼できるドメインのみを指定
    ドメインの所有権が変わる可能性を考慮する。
  • 最小権限の原則
    必要なプラグインのみを許可する。
  • HTTPSの使用
    通信の暗号化を必須とする。
  • 定期的な監査
    許可されたドメインと権限を定期的に見直しする。


CSP (Content Security Policy) の設定

 // src-tauri/tauri.conf.json
 {
   "app": {
     "security": {
       "csp": {
         "default-src": "'self'",
         "script-src": "'self' 'unsafe-inline'",
         "style-src": "'self' 'unsafe-inline' https://fonts.googleapis.com",
         "font-src": "'self' https://fonts.gstatic.com",
         "img-src": "'self' data: https:",
         "connect-src": "'self' https://api.example.com"
       }
     }
   }
 }



Runtime Authority

Runtime Authorityの基本

Runtime Authorityは、アプリケーション実行時に全てのパーミッション、Capabilities、Scopesを管理するコンポーネントである。

  • パーミッションの解決
    ウインドウとコマンドに基づいて適用されるパーミッションを決定する。
  • スコープの検証
    コマンドパラメータがスコープ内にあるかを検証する。
  • アクセス制御
    IPCコールごとにアクセス可否を判断する。


Authorityの動作フロー

サムネイルの作成エラー: ファイルがありません


Authorityのデバッグ

開発時にAuthorityの状態を確認する方法を以下に示す。

 // デバッグビルドでパーミッション情報を出力
 #[cfg(debug_assertions)]
 fn debug_permissions(app: &tauri::AppHandle) {
    if let Some(menu) = app.menu() {
       println!("Menu items: {:?}", menu.items());
    }
 
    // 現在のパーミッション状態をログ出力
    println!("Current authority state: {:?}", app.authority());
 }



設定ファイルの構造

ディレクトリ構成

src-tauri/
├── capabilities/
│   ├── default.json        # デフォルトCapabilities
│   ├── main-window.json    # メインウインドウ用
│   ├── settings.json       # 設定ウインドウ用
│   └── viewer.json         # ビューアウインドウ用
├── permissions/
│   ├── my-app.toml         # カスタムパーミッション定義
│   └── plugins/
│       └── custom.toml     # プラグイン用パーミッション
├── gen/
│   └── schemas/
│       └── desktop-schema.json  # 自動生成スキーマ
└── tauri.conf.json         # メイン設定ファイル


スキーマの使用

JSONファイルでオートコンプリートとバリデーションを有効にする:

 {
   "$schema": "../gen/schemas/desktop-schema.json",
   "identifier": "default",
   // ...略
 }


パーミッションの自動生成

Tauri CLIは、ビルド時にパーミッション定義を自動生成する。

# パーミッションを生成
cargo tauri build

# または開発モードで確認
cargo tauri dev



React + TypeScriptでのサンプルコード

セキュアなコマンド呼び出し

 // src/utils/secureInvoke.ts
 import { invoke } from '@tauri-apps/api/core';
 
 // 型安全なinvokeラッパー
 export async function secureInvoke<T>(
   command: string,
   args?: Record<string, unknown>
 ): Promise<T> {
   try {
     const result = await invoke<T>(command, args);
     return result;
   }
   catch (error) {
     // セキュリティエラーのハンドリング
     if (String(error).includes('not allowed')) {
       console.error('Permission denied:', command);
       throw new Error(`Permission denied for command: ${command}`);
     }
     throw error;
   }
 }
 
 // 使用例
 export async function readFile(path: string): Promise<string> {
   // パーミッションがない場合はエラーがスローされる
   return secureInvoke<string>('read_text_file', { path });
 }


パーミッションチェックユーティリティ

 // src/hooks/usePermissions.ts
 import { check } from '@tauri-apps/plugin-updater';
 import { useState, useEffect } from 'react';
 
 interface PermissionStatus {
   [key: string]: boolean;
 }
 
 export function usePermissions(commands: string[]) {
   const [permissions, setPermissions] = useState<PermissionStatus>({});
   const [isLoading, setIsLoading] = useState(true);
 
   useEffect(() => {
     const checkPermissions = async () => {
       setIsLoading(true);
       const status: PermissionStatus = {};
 
       // 各コマンドのパーミッションをチェック
       // 注意 : 実際のパーミッションチェックAPIは実装に依存
       for (const cmd of commands) {
         try {
           // テスト用の軽量なコマンドでパーミッションを確認
           // status[cmd] = await checkPermission(cmd);
           status[cmd] = true; // 仮実装
         }
         catch {
           status[cmd] = false;
         }
       }
 
       setPermissions(status);
       setIsLoading(false);
     };
 
     checkPermissions();
   }, [commands]);
 
   return { permissions, isLoading };
 }
 
 // 使用例
 function MyComponent() {
   const { permissions, isLoading } = usePermissions([
     'read_file',
     'write_file',
     'open_url'
   ]);
 
   if (isLoading) {
     return <div>Checking permissions...</div>;
   }
 
   return (
     <div>
       {permissions['read_file'] && (
         <button>Read File</button>
       )}
       {permissions['write_file'] && (
         <button>Write File</button>
       )}
     </div>
   );
 }


エラーハンドリング

 // src/utils/errorHandler.ts
 import { toast } from 'react-hot-toast';
 
 export class SecurityError extends Error {
   constructor(message: string) {
     super(message);
     this.name = 'SecurityError';
   }
 }
 
 export function handleInvokeError(error: unknown): never {
   const errorMessage = String(error);
 
   // パーミッションエラー
   if (errorMessage.includes('not allowed') || 
       errorMessage.includes('Permission denied')) {
     toast.error('この操作を実行する権限がありません');
     throw new SecurityError(errorMessage);
   }
 
   // スコープエラー
   if (errorMessage.includes('out of scope') ||
       errorMessage.includes('not in allow scope')) {
     toast.error('指定されたリソースへのアクセスが許可されていません');
     throw new SecurityError(errorMessage);
   }
 
   // その他のエラー
   toast.error(`エラーが発生しました: ${errorMessage}`);
   throw error;
 }
 
 // 使用例
 async function loadUserData() {
   try {
     const data = await invoke('get_user_data');
     return data;
   }
   catch (error) {
     handleInvokeError(error);
   }
 }



推奨される事柄

最小権限の原則

  • 必要なパーミッションのみを付与
    開発中は広めに設定して、本番では最小限に絞り込む。
  • ウインドウごとに権限を分離
    設定ウインドウにはファイルアクセス権限を与えない等
  • デフォルト拒否
    明示的に許可されていない操作は全て拒否される。


セキュリティ監査

# パーミッションの一覧を確認
cargo tauri info

# ビルド時のセキュリティチェック
cargo tauri build --no-bundle


定期的な見直し

  • 使用していないパーミッションを削除
    機能追加時に追加したパーミッションを確認する。
  • 依存関係の更新
    Tauriとプラグインを最新バージョンに維持
  • CVEの確認
    Tauriのセキュリティアドバイザリを定期的に確認する。


本番環境での推奨設定

 {
   "identifier": "production",
   "description": "Production-ready capabilities",
   "windows": ["main"],
   "permissions": [
     // 必要最小限のパーミッションのみ
     "core:default",
     "dialog:allow-message"
   ],
   "remote": {
     // リモートアクセスは原則無効
     "urls": []
   }
 }



トラブルシューティング

エラー : Command not allowed

  • 原因
    コマンドに対するパーミッションが設定されていない。
  • 解決方法
     // capabilities/default.jsonにパーミッションを追加
     {
       "permissions": [
         "your-plugin:allow-your-command"
       ]
     }
    


エラー : Path out of scope

  • 原因
    指定されたパスがスコープの許可リストに含まれていない。
  • 解決方法
     {
       "identifier": "fs:allow-read-text-file",
       "allow": [
         { "path": "$APPDATA/**" },
         { "path": "/custom/path/**" }
       ]
     }
    


エラー : Remote URL not allowed

  • 原因
    リモートドメインからのアクセスが許可されていない。
  • 解決方法
     {
       "security": {
         "dangerousRemoteUrlIpcAccess": [
           {
             "windows": ["main"],
             "domain": "trusted.example.com",
             "plugins": ["allowed-plugin"]
           }
         ]
       }
     }
    


Capabilities が反映されない

  • 原因
    設定ファイルの変更がビルドに反映されていない。
  • 解決方法
     # キャッシュをクリアして再ビルド
     cargo clean
     cargo tauri dev
    



関連情報