開発用に SSL 証明書エラーを無視する

Recipe ID: net-008

開発中のローカルサーバー(localhost)や、オレオレ証明書(自己署名証明書)を使用している内部サーバーに対して通信を行う際、SSL 証明書エラーを無視してリクエストを成功させる方法を解説します。

警告: この設定は中間者攻撃(Man-in-the-Middle attack)に対して脆弱になります。本番環境では絶対に使用しないでください。あくまで開発用、または信頼できる閉域網内でのデバッグ用として使用してください。

方法について

Tauri の標準 plugin-http を使用する場合、セキュリティの観点からデフォルトでは不正な証明書は拒否されます。
この挙動を変更するには、Rust 側で reqwest クライアントをカスタマイズして使用するカスタムコマンドを作成する方法が最も確実で一般的です。

前提条件

Cargo.tomlreqwest が必要です。

[dependencies]
reqwest = { version = "0.12", features = ["json", "rustls-tls"] }

実装手順 (Rust)

reqwest::ClientBuilderdanger_accept_invalid_certs(true) オプションを使用します。名前の通り「危険」な設定であるため、注意して使用してください。

src-tauri/src/lib.rs:

use tauri::command;

// 開発用: 証明書エラーを無視してGETリクエストを送るコマンド
#[command]
async fn fetch_unsafe(url: String) -> Result<String, String> {
    // クライアントの構築
    let client = reqwest::Client::builder()
        .danger_accept_invalid_certs(true) // ここで証明書検証を無効化
        .build()
        .map_err(|e| e.to_string())?;

    let res = client.get(&url)
        .send()
        .await
        .map_err(|e| e.to_string())?;

    res.text().await.map_err(|e| e.to_string())
}

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    tauri::Builder::default()
        .invoke_handler(tauri::generate_handler![
            fetch_unsafe // コマンドを登録
        ])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

使用方法 (JavaScript)

フロントエンドからは invoke を使用してこのコマンドを呼び出します。

import { invoke } from '@tauri-apps/api/core';

async function testLocalApi(): Promise<void> {
    try {
        // 自己署名証明書のサーバーへアクセス
        const response = await invoke<string>('fetch_unsafe', { 
            url: 'https://localhost:8443/api/debug' 
        });
        
        console.log('Response:', response);
    } catch (err) {
        console.error('Connection failed:', err);
    }
}

Tips: 開発モードのみ有効にする

誤って本番ビルドに含まれるのを防ぐため、Rust の条件付きコンパイル(Feature フラグや cfg 属性)を使用することをお勧めします。

#[command]
async fn fetch_data_wrapper(url: String) -> Result<String, String> {
    let mut builder = reqwest::Client::builder();

    // デバッグビルド(dev)の時のみ、証明書エラーを無視
    #[cfg(debug_assertions)]
    {
        builder = builder.danger_accept_invalid_certs(true);
    }

    let client = builder.build().map_err(|e| e.to_string())?;
    
    // ... リクエスト処理
    let res = client.get(url).send().await.map_err(|e| e.to_string())?;
    res.text().await.map_err(|e| e.to_string())
}

注意点

* Webview の通信: この設定は Rust 側からの通信にのみ適用されます。<img src="...">window.fetch など、Webview が直接行う通信で自己署名証明書を通すには、アプリ起動時の引数に --ignore-certificate-errors を渡すなどの別の対策が必要ですが、これはアプリ全体のセキュリティレベルを下げるため、基本的には推奨されません。
* Android / iOS: モバイルターゲットの場合、OS レベルのネットワークセキュリティ設定(ATSやNetwork Security Config)が優先され、Rust 側で無視設定をしてもうまく動作しない場合があります。