世界を動かす技術を、日本語で。

少ない方が安全:オブシディアンがサプライチェーン攻撃のリスクを低減する方法

概要

  • Obsidian はサプライチェーン攻撃対策を徹底した設計
  • 依存ライブラリを極力減らし 独自実装 を重視
  • 依存関係は 厳密なバージョン管理 とロックファイルで制御
  • アップグレードは慎重かつ段階的 に実施
  • 多層的な安全対策で 利用者のプライバシーと安全 を確保

Obsidianのサプライチェーン攻撃対策

  • サプライチェーン攻撃は 悪意あるアップデート がオープンソースコードに紛れ込むリスク
  • Obsidian では依存する外部コードを最小限に抑制
    • 同カテゴリの他アプリと比較して 依存数が少ない 特徴
    • 依存ライブラリ一覧は Creditsページ で公開
  • 機能(例:Bases, Canvas)は 市販ライブラリを使わず独自実装
    • 実装の完全なコントロール性確保
  • 小規模ユーティリティは 自前実装 が基本
  • 中規模モジュールは ライセンス許諾範囲でフォークし内包
  • 大規模ライブラリ(例:pdf.js, Mermaid, MathJax)は
    • 既知の安全なバージョンファイル を直接同梱
    • アップグレードは セキュリティ修正時など必要最小限
    • アップグレード時は リリースノート精読・変更差分確認・徹底検証
  • 依存関係のグラフが浅く サブ依存も最小限
    • 攻撃が紛れ込むリスクの低減

実際にアプリに含まれるもの

  • 実際のアプリに含まれるパッケージは Electron, CodeMirror, moment.js などごく一部
  • ビルド時のみ使うパッケージ(例:esbuild, eslint)は ユーザー環境に含まれない

バージョン管理とロックファイル運用

  • 全依存関係は厳密なバージョン指定 とロックファイルで管理
    • ロックファイルがビルド時の 唯一の参照元
    • これにより 再現性のあるインストール変更監査の容易化 を実現
  • postinstallスクリプトは不使用
    • インストール時の 任意コード実行リスクを排除

アップグレード運用方針

  • 依存関係のアップデートは 慎重かつ段階的
    • 変更履歴を逐一確認
    • 新バージョンで追加された サブ依存も精査
    • 変更が大きい場合は 差分比較
    • 自動・手動テスト で主要動作を確認
    • レビュー通過後のみロックファイルを更新
  • 実際のアップデート頻度は 非常に低い
    • 安定稼働を優先し 頻繁な変更を避ける
    • アップデート時は 新規依存追加と同等の慎重さ

時間的バッファの活用

  • リリース前に十分な遅延期間 を設ける運用
    • その間に コミュニティやセキュリティ研究者による検知 が期待できる
    • 問題のあるバージョンは 出荷前に発見されやすい

多層防御によるリスク低減

  • 単一の対策だけでなく
    • 依存数削減
    • 浅い依存グラフ
    • 厳密なバージョン固定
    • postinstall排除
    • 慎重なアップグレード
  • これらの多層的アプローチで サプライチェーン攻撃のリスクを大幅に低減
  • コードがユーザーに届く前に問題を発見できる長い猶予期間 を確保

さらなるセキュリティ情報

  • Obsidianの広範なセキュリティ方針や過去の監査 については
    • 公式 Securityページ監査報告書 を参照

Hackerたちの意見

他のアプリを使ってメモや共有をしてるから、これを読むのはいいし、考える価値があるね。でも、ObsidianってElectronアプリじゃなかったっけ?Electronってリソースをめっちゃ使うイメージがあるし、ネイティブじゃないよね。JavaScriptって「安全」って感じがしないんだけど、俺が時代遅れなのかな?

JavaScriptはかなり安全な言語だよ。ブラウザは世界規模で安全なJavaScriptを実行するのに大成功してるし、使ってるウェブサイトは全部JavaScriptを動かしてて、他のサイトのデータを読み取れないんだ。Electronも同じで、v8を使ってJavaScriptをサンドボックス化してる。ユーザー入力をそのサンドボックス内で実行しない限り(多くのプログラミング言語が許可してることだけど、JSも含めて)、かなり安全だよ。サプライチェーン攻撃の問題はnpmに特有のもので、JSとは関係ない。npmは最近の攻撃に対してもっと責任を持つべきで、依存関係を公開する際にもっと厳しいセキュリティ管理を強制する必要があるね。

JavaScriptは、おそらく地球上で最も使われている言語の一つだよ。ほとんどのコンピュータや基本的に全てのスマホで動いてるし、これによって多くのセキュリティ問題が発見されることになる。なんで「ネイティブ」アプリがもっと安全だと思うの?

Electronがあんまり好きじゃないけど(Tauriに感謝)、Obsidianは素晴らしいアプリだから、Electronで敬遠する必要はないよ。MCPを接続して、エージェントが個人の知識ベースとして使うこともできるし、かなり便利だよ。

リソースをかなり使うんだよね。PCでは問題ないけど、何千ものノートが入ったObsidianのボールトは、モバイルだとプラグインを無効にしても起動が遅くなることがある。ユーザーはクイックキャプチャプラグインやアプリでこの問題を回避するけど、もっとシンプルなネイティブ版のObsidianがあればいいのに。

いや、実際にはそんなに問題じゃないよ。GitHubやVS CodeもElectronアプリだし、SlackやDiscordもそう。Postmanもそうだよね。ちょっと聞きたいんだけど…マークダウンのノートアプリで何をしてるの?パフォーマンスが問題になる理由は何?もしかして、ThinkPad 701CのLynxセッションでこれを読んでるの?

HTMLをレンダリングする必要があるなら、結局マークダウンはそうなるから、ウェブブラウザを使った方がいいかもね。

JavaScriptはC++よりもずっと安全だよ。だって、メモリ管理された言語だからね。

そうだよ、ユーザーに送るコードには責任があるからね。依存関係を固定しないのはトラブルを招くことになるよ。まさに「インターネットからランダムなコードをダウンロードして、うまくいくことを願う」って感じ。

固定した依存関係も、結局はその依存関係がさらに依存関係を持ってるから、常にランダムなコードをダウンロードしてることになるよ。いや、ほんと、Electronと一緒にどれだけのコードがついてくるか考えると…

依存関係を固定するってことは、固定したバージョン以降に出たセキュリティ修正を逃すことにもなるから、それもトラブルを招くことになるよ。だから、これらの修正に気づくためのメカニズムが必要で、修正をバックポートするか、それを含むバージョンにアップグレードする必要があるね。

これは一つの見方だけど、ほとんどのユーザーがサードパーティのコミュニティプラグインを使ってるってことを無視してるね。Obsidianのプラグインはセキュリティモデルが本当にひどい。自分で作ってみて気づいたけど、Obsidianのプラグインはボールト内の全てのファイルに完全にアクセスできちゃうんだ。Obsidianはもっと「バッテリー内蔵」にする選択肢もあったはずだけど、開発の手間がかかるからコミュニティに任せてる。これが攻撃面を大幅に増やしてるんだよね。プラグインが使う全ての権限を宣言するブラウザ拡張機能を持って、許可されてない権限にアクセスしようとしたらブロックされるようにすることもできたはず。どちらのアプローチも「サードパーティの依存関係が少ない」よりも、エンドユーザーにとってもっと実際的なセキュリティを提供できたはずだよ。

プラグインモデルって大体こんな感じじゃない?VSCodeとかVim、Emacsとかは、コンテンツを分けるために何かしてるのかな?ゲームだけは、プラグインの権限が制限されてることが多い気がする。

商業用のObsidianプラグインを開発してるんだ。特定のグレードのプラグインに対して、もっと厳しい審査があればいいのにと思う。個人的には、Arch Linuxのaurみたいに、コミュニティが管理するプラグインリポジトリと、もっと厳選された小規模なものを作ってほしい。それがプラグインのレビュー時間の短縮にもつながると思う。

ここで関連するオープンレターがあるよ:https://www.emilebangma.com/Writings/Blog/An-open-letter-to-...

面白いことに、さっきArch Linuxとその派生について考えてたんだ。redditで、彼らは小さな予算で運営してるって言われてた。メンテナーが、彼らは非常に低いオーバーヘッドで運営してるって返事してて、私が思ったのは、私が使ってるソフトウェアのほとんどはAURから来てて、ユーザーが自分のセキュリティを管理することに頼ってるってこと。エンジニアが自分のセキュリティすら管理できないのに、ユーザーにそれを期待するのはどうなんだろう?

Obsidianのプラグインは、ボールト内のすべてのファイルに完全かつ制限なしのアクセス権を持っている。何かが変わらない限り、それ以上に悪いこともある。プラグインは、あなたのマシン上のどんなファイルにも無制限にアクセスできる。以前、ディスコードでこのことを話したとき、みんな軽く流された。

若い頃、ソフトウェアの世界には、ビデオゲームデザインから従来のソフトウェアにアイデアが流れているって話をする著名人が何人かいたんだ。でも、最近はそういう話をする人を全然聞かないな(私がそれを繰り返している場合を除いて)。それはちょっと残念だね。例えば、Blizzardの古参の人がWorld of Warcraftのプラグインシステムについて、特に最初の10年間にどう機能していたか、どこが壊れたか、どうやって時間をかけて強化したか、プラグインからコアライブラリへの機能のバックポートのプロセスについて本か少なくとも短編小説を書いたら、ソフトウェアコミュニティにとって大きな利益になると思う。多くのエコシステムは、雑で半端なプラグインシステムを作ってるからね。大半は、少なくとも三つのうち二つの特徴で説明できると思う。

vscodeより悪くはないよ。確かに権限はあるけど、拡張機能がプロセスを開始するのは超一般的で、そのプロセスは好きなことができるからね。

Obsidianのプラグインでデータを抜き取るのがバレるのも時間の問題だと思う。 reputational harmが大きくなったら、チームも安全対策を導入し始めるんじゃないかな。最低限、何かしらの認証されたパブリッシャーシステムを作るべきだよね。

ほとんどのユーザーはサードパーティのコミュニティプラグインを使ってる これって本当?どれくらいのObsidianユーザーがサードパーティのプラグインを使ってるかの情報はあるの?私は使ってないし、そもそもObsidianはデフォルトで「制限モード」で動いてて、コミュニティプラグインを使うには特別に有効化しないといけないんだよね。だから、そうする人はリスクを理解してると思う。どれくらいの人がその設定を有効にするんだろう?私にとっては、セキュリティが最優先ってわけじゃなくて、Markdownの魅力はシンプルさと相互運用性なんだよね。「プラグイン」に依存すればするほど、この特定のプラットフォームに縛られちゃう気がする。

もっと「バッテリー同梱」にする選択肢もあったけど、開発の手間が増えるからコミュニティに任せてるんだよね。それが攻撃面を大幅に増やすことになるんだけど。ああ、WordPressモデルだね。

最近、ちょっと理解に苦しんでいるアドバイスがあるんだけど、新しいパッチがリリースされたときに依存関係を更新しない方がいいっていう考え方なんだよね(例えば、X.X.PATCH)。新しいパッチを更新しないことで、マルウェアを誤ってインストールするリスクが減るのは分かるけど、パッチってセキュリティを改善するために定期的にリリースされてるんじゃないの?新しいパッチをインストールしないのは、一般的に考えて賢明じゃないと思うんだけど。

新しいパッチがリリースされるまで少し待つってことだと思う。完全にアップデートを避けるわけじゃないよ。最近は妥協点がすぐに見つかるみたいで、だいたい数時間以内にね。npmパッケージのリリースを監視している会社がいくつかあって、彼らはセキュリティスキャンの製品を売っているから、常に最新情報を把握しているのがビジネスの一部なんだ。pnpmには、パッケージをインストールするために少なくともX分古くなっている必要があるって設定があるよ。安全のために、少なくとも24時間は待つかな。 https://pnpm.io/settings#minimumreleaseage

このパズルには重要な欠けた部分がある。それは、なぜアップデートをするのか、パッチが何であるかを理解することだ。誰もソースコードを読む時間なんてないけど、リリースノートの簡単な要約を教えてくれるツールやサービスがたくさんあるよ。例えば、npm Auditはパッケージのバージョンにおけるセキュリティ脆弱性をリストアップしてくれる。私は、必要な場合を除いて更新しないって戦略を取ってる。アップデートは攻撃ベクトルになるだけでなく、非常に一般的なバグの原因にもなるからね。でも重要なのは、自分がどんな脆弱性にさらされているかを把握しておくこと。脆弱性を持ったパッケージは常に出てくるけど、もしそれが自分が使っていない部分のReDoS脆弱性だったら、特にユーザー入力を渡さない部分なら、そのまま放置しておくことにするよ。もし他のパッケージが安全に使わないかもしれないものだったら、脆弱性を知っておけば、その重要性を判断して、すぐにアップデートが必要か、あるいは(できれば)パッチが実際に使われるまで待てるか決められる。それがこの文脈でのセキュリティについて覚えておくべき重要なことだよ:それはアクティブで継続的なプロセスなんだ。組織のリスク許容度やリスク嗜好に合わせて調整する必要があるもので、「絶対にアップデートしない」や「常にアップデートする」といった一律のものではない。しっかりしたセキュリティスタンスを持つためには、それ以上の情報が必要なんだ。

2週間前に私のパッケージに攻撃があったのは、まさにこの仮定を利用したパッチリリースだった。ポストインストールスクリプトでもなかったし。最新の自動スキャンとか色々あるけど、これはほぼ無意味なポイントだと思う。パッケージが脆弱だって分かる時は、警告音がうるさくて明確だからね。私は本当にそう思うし、サプライチェーン攻撃を気にするなら、バージョン範囲は最悪のものだってずっと言ってきたよ。

正直言うと、今はローカル環境でフロントエンドのビルドプロセスを隔離しようか考えてる。OPENAI_API_KEYや.ssh/*のようなローカル環境変数をリモートマシンに送るのはそんなに難しくない気がする。Pythonや他の言語のプロジェクトと比べてもあまり変わらないのは分かってるけど、今のところNode.jsコミュニティを信頼できない気がしてる。

Dockerコンテナ内でviteを動かすのが一番良さそうだね。

Denoに切り替えるのもいいかも。デフォルトでサンドボックス化されてるし、細かい設定ができるから、特定の環境変数にアクセスしたり、特定のファイルを読み書きしたりする必要があるスクリプトも、そういうアクセスだけ許可するように簡単に設定できるよ。

私たちはpostinstallスクリプトを実行しません。これにより、パッケージがインストール中に任意のコードを実行するのを防ぎます。意図は分かるけど、これが本当に大きな意味を持つのかは分からない。もしパッケージが侵害されていたら、全体がすでに信頼できないし、postinstallをスキップしたからといって他のコードが突然安全になるわけじゃない。もし侵害されていなければ、正当なインストール手順を壊すリスクがある。セキュリティの観点から見ると、ちょっと変なトレードオフに感じる。具体的なデータは持ってないけど、定期的なアップデートでパッチされた脆弱性の方が、実際のサプライチェーンの侵害よりもずっと多いと思う。一般的にアップデートを遅らせたりブロックしたりすることは、リスクを減らすどころか、むしろ増やす傾向がある。

ソフトウェアがいろんなことをできるのに、「少ない」って言葉を使うのはちょっと変だよね。シンプルなメモ取りツールじゃないんだから。

既知の安全なバージョンの依存関係をピン留めすることで、どれだけサプライチェーンの脆弱性が軽減できるんだろう?そもそも最新のxzバージョンが必要だった人っているの?例えば2022年のリリースをピン留めした場合、どんな悪影響があったんだろう。

ネイティブアプリを求めている人や、サプライチェーンリスクをさらに減らしたい人には、GTKを使っていて主要なLinuxディストリビューションにパッケージされているZimがオススメだよ。

でもZimにはネイティブのスマホアプリや同期機能がないから、そこがObsidianの大きな魅力なんだよね。プラグインを無闇にインストールしなければ、かなり安全だよ。

ObsidianはElectronアプリだから、膨れやセキュリティの欠如は仕方ないよね。

それに、使っているどのプラットフォームでも見た目や使い心地が全く同じで、アクセシビリティもネイティブでサポートしてるんだ。