Improved the security of the connection between the app window and AI Studio (#1146)

This commit is contained in:
Thorsten Sommer authored and GitHub committed 2026-11-01 12:29:37 +01:00
1 parent 64dc621a7d
commit faae2951f7
26 files changed
+1056 -88

No files matched your search

+19 -3
View File
@@ -8,6 +8,7 @@ root, which applies here as well.
Key modules:
- `app_window.rs` - Tauri window management, updater integration
- `app_access.rs` - Session cookie which lets the app window into the .NET server
- `dotnet.rs` - Launches and manages the .NET sidecar process
- `runtime_api.rs` - Axum-based HTTPS API for .NET ↔ Rust communication
- `certificate.rs` - Generates self-signed TLS certificates for secure IPC
@@ -25,6 +26,21 @@ a route added afterward would be open to every process on the machine. The test
`every_route_requires_the_api_token` reads the routes from `create_router` and fails for any route
which answers without the token.
**Only the app window gets into the .NET server.** Every start makes a new UI token in `app_access.rs`.
Rust passes it to .NET as `AI_STUDIO_UI_TOKEN` through `ipc_environment` in `dotnet.rs`, and hands it to
the window as an HttpOnly session cookie before the window opens the app (`change_location_to` in
`app_window.rs`); .NET refuses every request without it. Therefore:
- Never put the token into a URL, a log line, or `startup.env`. Only a development build writes a boot
link, to `dev-boot-link.txt` in the repository root, so that another browser can get the cookie.
- Keep the cookie `Lax`. A release shows `tauri://localhost` before it opens the app, and WKWebView on
macOS withholds a `Strict` cookie on that navigation. A development build starts from the dev server
of the Tauri CLI on `127.0.0.1`, the same site as the app, which hides the problem; start it with
`cargo tauri dev --no-watch --no-dev-server` to see what a release sees.
- The .NET server listens on `127.0.0.1` only, and the cookie belongs to that host. Change the host in
`APP_HOST` and in `Program.cs` together, since no test compares them. `AppAccessRuntimeAgreementTests`
only checks that both sides use the same cookie name and environment variable.
**Runtime API handlers never block.** All calls of the .NET app share one HTTP/2 connection, and the
task driving it may wait on exactly the Tokio worker which a blocking handler occupies, so a single
blocking handler can hold up the whole app. Therefore:
@@ -47,8 +63,8 @@ blocking handler can hold up the whole app. Therefore:
## IPC Communication Flow
1. Rust runtime starts and generates TLS certificate
2. Rust starts internal HTTPS API on random port
3. Rust launches .NET sidecar, passing: API port, certificate fingerprint, API token, secret key
3. Rust launches .NET sidecar, passing: API port, certificate fingerprint, API token, secret key, UI token
4. .NET reads environment variables and establishes secure HTTPS connection to Rust
5. .NET requests an app port from Rust, starts Blazor Server on that port
6. Rust opens Tauri webview pointing to localhost:app_port
5. .NET requests an app port from Rust, starts Blazor Server on 127.0.0.1 at that port
6. Rust hands the session cookie to the Tauri webview and points it to 127.0.0.1:app_port
7. Bi-directional communication: .NET ↔ Rust via HTTPS API