一、背景引入

在开发软件的时候,我们经常会碰到要处理敏感信息的情况,像密码、API 密钥这些。要是把它们直接存到本地配置文件里,就跟把家门钥匙随便扔在门口一样不安全。因为本地配置文件可能泄露,一旦泄露出去,敏感信息就落入不法分子手里了,后果不堪设想。不过别担心,Tauri 能和系统密钥环结合起来,帮我们实现安全的读写操作。下面咱们就详细说说这事儿。

二、Tauri 和系统密钥环介绍

2.1 Tauri 简介

Tauri 是一个用来构建跨平台桌面应用程序的框架,它就像一个万能工具箱,能让开发者用前端技术(像 HTML、CSS、JavaScript)来开发桌面应用。它的优点可多啦,生成的应用体积小,启动速度快,还能很好地兼容不同的操作系统。比如说,你用 Tauri 开发了一个简单的笔记应用,它能在 Windows、Mac 和 Linux 系统上都正常运行。

2.2 系统密钥环介绍

系统密钥环是操作系统提供的一个安全存储敏感信息的地方。它就好比一个带锁的保险箱,能对存储的信息进行加密,只有经过授权的程序才能访问。不同的操作系统有不同的密钥环实现,像在 Windows 上是 Credential Manager,在 macOS 上是 Keychain,在 Linux 上有 GNOME Keyring 等。举个例子,当你在 Safari 浏览器里保存网站密码时,这个密码其实就是存储在 macOS 的 Keychain 里的。

三、传统本地配置文件存储敏感信息的问题

3.1 安全性问题

把敏感信息存到本地配置文件里,信息是明文存储的。一旦配置文件被别人拿到,里面的敏感信息就一览无余。比如说,你把数据库的登录密码存到了一个名为 config.ini 的文件里,别人只要打开这个文件,就能看到密码。而且,如果你的电脑被黑客攻击,这种方式存储的信息就更容易被窃取了。

3.2 维护困难

当应用程序更新或者需要修改敏感信息时,直接修改配置文件很容易出错。要是不小心改错了一个字符,可能就会导致应用程序无法正常运行。而且,如果有多台设备需要同步配置信息,手动去修改每台设备上的配置文件会非常麻烦。

四、Tauri 结合系统密钥环实现安全读写方案

4.1 环境搭建

首先,你得保证已经安装了 Tauri 的开发环境。可以按照下面的步骤来安装:

# 安装 Tauri 的脚手架工具
cargo install create-tauri-app
# 创建一个新的 Tauri 项目
npx create-tauri-app my-app --template vanilla
cd my-app

这些命令的作用分别是:第一条是安装 Tauri 的脚手架工具,有了它咱们就能快速创建 Tauri 项目;第二条是创建一个基于香草模板(Vanilla)的新项目,叫 my-app;第三条是进入刚创建的项目目录。

4.2 引入依赖

在 Tauri 项目里,咱们要用到 tauri-plugin-keychain 这个插件来和系统密钥环交互。在 Cargo.toml 文件里添加下面的依赖:

[dependencies]
# 引入 Tauri 运行时
tauri = { version = "1.0.0", features = ["api-all"] }
# 引入 Tauri 密钥环插件
tauri-plugin-keychain = "0.1.0"

[build-dependencies]
# 构建时依赖 Tauri 构建工具
tauri-build = "1.0.0"

[features]
# 插件特性
all-plugins = ["tauri-plugin-keychain"]
default = ["all-plugins"]

这段代码是告诉项目需要用到哪些插件和工具,比如 Tauri 本身和 tauri-plugin-keychain 插件。

4.3 编写读写代码

src-tauri/src/main.rs 文件里编写和系统密钥环交互的代码,下面是一个例子:

use tauri::App;
use tauri_plugin_keychain::Keychain;

fn main() {
    tauri::Builder::default()
       .plugin(Keychain::default())
       .setup(|app| {
            let app_handle = app.handle();
            // 保存敏感信息到系统密钥环
            #[cfg(target_os = "macos")]
            let _ = app_handle
               .keychain()
               .set("my_app_key", "my_sensitive_data")
               .expect("Failed to save to keychain");

            // 从系统密钥环读取敏感信息
            #[cfg(target_os = "macos")]
            let data = app_handle
               .keychain()
               .get("my_app_key")
               .expect("Failed to read from keychain");
            println!("Read data from keychain: {}", data);

            Ok(())
        })
       .run(tauri::generate_context!())
       .expect("error while running tauri application");
}

这段代码的意思是,先引入必要的模块和插件,然后在 main 函数里设置 Tauri 应用。在 setup 函数里,我们先把敏感信息 "my_sensitive_data" 保存到系统密钥环里,用 "my_app_key" 作为这个信息的标识。接着,再从密钥环里读取这个标识对应的信息并打印出来。这里的 #[cfg(target_os = "macos")] 是为了让代码只在 macOS 系统上运行,不同系统的部分操作可能会有差别。

4.4 前端调用

如果你想在前端调用这些读写操作,可以在 HTML 页面里添加一些 JavaScript 代码。比如说,在 src/index.html 里添加下面的代码:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>My Tauri App</title>
    <!-- 引入 Tauri 的 JavaScript API -->
    <script src="/tauri.js"></script>
</head>

<body>
    <button id="save-btn">Save to Keychain</button>
    <button id="read-btn">Read from Keychain</button>
    <div id="output"></div>

    <script>
        // 为保存按钮添加点击事件监听器
        document.getElementById('save-btn').addEventListener('click', async () => {
            try {
                // 调用 Tauri 命令保存信息到密钥环
                await window.__TAURI__.invoke('save_to_keychain', { key: 'my_app_key', value: 'new_sensitive_data' });
                document.getElementById('output').textContent = 'Data saved to keychain';
            } catch (error) {
                document.getElementById('output').textContent = `Error: ${error}`;
            }
        });

        // 为读取按钮添加点击事件监听器
        document.getElementById('read-btn').addEventListener('click', async () => {
            try {
                // 调用 Tauri 命令从密钥环读取信息
                const data = await window.__TAURI__.invoke('read_from_keychain', { key: 'my_app_key' });
                document.getElementById('output').textContent = `Read data: ${data}`;
            } catch (error) {
                document.getElementById('output').textContent = `Error: ${error}`;
            }
        });
    </script>
</body>

</html>

这段 HTML 代码创建了两个按钮,一个是保存数据到密钥环,另一个是从密钥环读取数据。当点击保存按钮时,会调用 save_to_keychain 这个 Tauri 命令,把新的敏感信息保存到密钥环里。点击读取按钮时,会调用 read_from_keychain 命令从密钥环里读取信息,并把结果显示在页面上。

同时,在 src-tauri/src/main.rs 里要添加对应的命令处理逻辑:

use tauri::App;
use tauri_plugin_keychain::Keychain;

#[tauri::command]
// 定义保存到密钥环的命令处理函数
async fn save_to_keychain(app: tauri::AppHandle, key: String, value: String) -> Result<(), String> {
    app.keychain()
       .set(&key, &value)
       .map_err(|e| e.to_string())
}

#[tauri::command]
// 定义从密钥环读取的命令处理函数
async fn read_from_keychain(app: tauri::AppHandle, key: String) -> Result<String, String> {
    app.keychain()
       .get(&key)
       .map_err(|e| e.to_string())
}

fn main() {
    tauri::Builder::default()
       .plugin(Keychain::default())
       .invoke_handler(tauri::generate_handler![save_to_keychain, read_from_keychain])
       .run(tauri::generate_context!())
       .expect("error while running tauri application");
}

这里定义了两个命令处理函数,save_to_keychain 用于保存信息,read_from_keychain 用于读取信息。然后在 main 函数里把这两个函数注册到 Tauri 应用里,这样前端调用的时候就能找到对应的处理逻辑了。

五、应用场景

5.1 桌面应用登录

在一些桌面应用里,用户登录时输入的用户名和密码属于敏感信息。使用 Tauri 结合系统密钥环,能把这些信息安全地存储起来。下次用户登录时,应用可以直接从密钥环里读取信息,自动填充登录表单,既方便又安全。比如说,一个邮件客户端应用,用户第一次登录时输入账号密码,应用把这些信息存到密钥环,下次打开应用就不用再手动输入了。

5.2 API 密钥管理

很多应用需要使用第三方的 API 密钥来调用服务,比如调用天气 API 获取天气信息。这些 API 密钥是非常敏感的,如果泄露出去,可能会导致安全问题。通过 Tauri 和系统密钥环,能把 API 密钥安全存储,应用在需要调用 API 时,从密钥环里读取密钥,保证了 API 密钥的安全性。

六、技术优缺点

6.1 优点

  • 安全性高:系统密钥环本身有加密机制,能对敏感信息进行加密存储,大大降低了信息泄露的风险。
  • 兼容性好:Tauri 是跨平台的框架,系统密钥环在不同操作系统都有对应的实现,所以这个方案能很好地在不同操作系统上运行。
  • 使用方便:开发者只需要使用 tauri-plugin-keychain 插件提供的 API 就能轻松实现读写操作,不需要自己去处理复杂的加密和解密逻辑。

6.2 缺点

  • 系统依赖:这个方案依赖于操作系统的密钥环功能,如果操作系统的密钥环出现问题,可能会影响应用的正常使用。比如,在某些 Linux 系统上,如果没有正确配置 GNOME Keyring,就可能会导致无法正常读写信息。
  • 性能影响:和直接读写本地文件相比,和系统密钥环交互可能会稍微慢一些,因为要经过操作系统的安全验证和加密解密操作。

七、注意事项

7.1 权限问题

在使用系统密钥环时,应用需要有相应的权限才能访问。比如在 macOS 上,应用需要在 Info.plist 文件里添加相应的权限声明,否则无法访问系统 Keychain。

7.2 错误处理

在读写系统密钥环时,可能会出现各种错误,比如密钥环满了、权限不足等。开发者要对这些错误进行合理的处理,给用户友好的提示信息。在前面的代码示例里,我们已经对可能出现的错误进行了捕获,并输出错误信息。

7.3 数据备份

虽然系统密钥环是比较安全的存储方式,但还是建议开发者对敏感信息进行定期备份,以防万一。

八、文章总结

把敏感信息存到本地配置文件确实存在很大的安全隐患,而 Tauri 结合系统密钥环提供了一种安全可靠的读写方案。通过使用 tauri-plugin-keychain 插件,开发者能方便地和系统密钥环交互,实现敏感信息的安全存储和读取。这个方案在桌面应用登录和 API 密钥管理等场景都非常实用。不过,在使用过程中要注意权限问题、错误处理和数据备份等方面。总之,Tauri 结合系统密钥环是一种值得推荐的处理敏感信息的方式,能让我们的应用更加安全可靠。