Skip to content

security: トークン取り扱いの機械的担保 — Debug redaction / bindings 非露出ガードテスト / legacy token 列の整理 #780

Description

@hitalin

背景

同ドメインの Misskey マルチカラムクライアント onodai145/tsumugi(Tauri v2 + Rust + Svelte)とのアーキテクチャ比較で、トークン封じ込めの「機械的な担保」に差があることが分かった。

notedeck は AccountPublichasToken: booleansrc/bindings.ts:2285)でフロントへのトークン露出を型レベルで防げているが、tsumugi はさらに一段深く、**「漏れない設計」ではなく「漏れたら CI が落ちる仕組み」**まで持っている。

tsumugi 側の実装(参考):

  • api/client.rs — クライアント構造体の Debug 実装で token を <redacted> に伏せる(ログ・panic メッセージ経由の漏洩防止)
  • lib.rsgenerates_frontend_bindings テスト — 生成された TS bindings に token: フィールドが含まれないことを assert!(!ts.contains("token:")) で検証
  • エラー型のコメントで「token 等の機微情報は含めない」を規約化

notedeck 側の現状ギャップ

  1. Account#[derive(Debug)] で token を素通し(notecli src/models.rs:17-29)。Drop での zeroize はあるが、{:?} でログに出せば平文で漏れる。AuthResultmodels.rs:1045-1051)も同様。
  2. bindings スナップショットテストは「陳腐化検知」のみsrc-tauri/tests/bindings_snapshot.rs)で、内容の不変条件(アカウントトークン非露出)を検証していない。将来誰か(未来の自分や AI エージェント含む)が Account をうっかり specta export しても CI は通ってしまう。
  3. accounts.token TEXT NOT NULL 列が schema に残存(notecli migrations/V1__initial_schema.sql:8)。keychain 移行済み・clear_token()db.rs:309)はあるが、平文トークンの受け皿が DB に残り続けている。

提案

  • Account / AuthResult に手書き Debug 実装(token を <redacted> に)
  • bindings_snapshot.rs に不変条件テストを追加: 生成 TS に raw トークンフィールドが出ないことを assert。CreatedApiToken.token(ローカル HTTP API 用・発行時 1 回のみ返す設計)は意図的な露出なので allowlist 化する
  • マイグレーションで accounts.token 列を NULL 許容化 or 削除し、平文トークンの永続経路を閉じる(新規行が常に空であることの担保)

参考

tsumugi の該当実装: https://github.com/onodai145/tsumugisrc-tauri/src/api/client.rs, src-tauri/src/lib.rs の bindings テスト)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

🔒SecuritySecurity related issue/PR🛠️DevDevelopment of NoteDeck itself

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions