PlainApp セキュリティ詳細ガイド

PlainApp がローカル Wi-Fi 上でどのようにデータを保護しているか — オープンソースコードに基づく解説です。

なぜローカルネットワークのセキュリティが重要なのか?

PC のブラウザから Android スマートフォンを管理するアプリを使うと、SMS、写真、連絡先、ファイルが Wi-Fi ネットワーク上を流れます。多くのアプリはこれらすべてを読み取り可能な平文で送信します。同じネットワーク上にいる誰もがその内容を見ることができます。

「自宅の Wi-Fi だから誰も覗かないだろう」と思うかもしれません。しかし、以下のケースを考えてみてください:

  • 公衆 Wi-Fi — カフェ、空港、ホテル — 近くにいる誰でも通信を傍受できます
  • 共有ネットワーク — ルームメイト、ゲスト、または侵害された IoT デバイスが存在する環境です
  • ルーターの脆弱性 — 既知の脆弱性を含む古いファームウェアが使われている場合があります

アプリが SMS メッセージを HTTP で平文のまま送信していれば、Wireshark のような無料ツールを使って誰でも内容を読めます。これは理論上の話ではなく、極めて簡単に実行可能です。

ほとんどのスマートフォン管理アプリがまさにこれをしています。Web UI を使用中に Chrome DevTools(F12 → Network タブ)を開けば、すべての API 呼び出しが平文の JSON で読めます — SMS の本文、ファイルパス、連絡先の名前、すべてです。

PlainApp はどこが違うのか

PlainApp は暗号化と認証を複数のレイヤーで適用しています。各レイヤーの役割をわかりやすく説明します。

Security Architecture Comparison
1

GraphQL API — 必要なデータだけを取得

多くのアプリは従来の REST API を使用しており、リソースごとに URL があり、必要かどうかに関わらずすべてのデータを返します。PlainApp は GraphQL を採用しています。これはブラウザが必要なデータだけを正確にリクエストできる、モダンなアプローチです。

これが重要な理由:

  • データ露出の最小化 — ファイル名だけが必要な場合、送信されるのはファイル名だけです
  • エンドポイントが一つだけ — 何十もの URL ではなく単一の /graphql URL を使用するため、攻撃対象が減ります
  • クエリごとの権限チェック — 各クエリは個別の権限を確認します(例:ログイン後でも SMS の読み取りには READ_SMS 権限が必要です)
2

暗号化された API 通信(XChaCha20-Poly1305)

これが PlainApp と他の多くの競合アプリとの最大の違いです。

すべての API リクエストとレスポンス——HTTP と WebSocket の両方の通信——は、HTTP モードでも HTTPS モードでも XChaCha20-Poly1305 で暗号化されます。これは WireGuard VPN、Cloudflare、Google の Tink ライブラリで使用されている最新の AEAD 暗号化アルゴリズムです。

わかりやすく言うと:

  1. 1ブラウザがリクエストを作成します(例:「SMS を見せて」)
  2. 2リプレイ攻撃防止のためにタイムスタンプとランダムな nonce を付加します
  3. 3XChaCha20-Poly1305 でペイロード全体を読み取り不能なバイナリデータに暗号化します
  4. 4暗号化されたバイナリがそのままネットワーク上を流れます——base64 変換なし、JSON なし、純粋なバイナリです
  5. 5あなたのスマートフォンだけが復号・検証できます

誰かが通信を傍受しても、見えるのは意味のないバイナリデータであり、読み取り可能な JSON ではありません。

Encrypted API Flow

暗号化の詳細:

  • 256 ビット鍵(極めて強力です)
  • 192 ビット nonce(他の暗号方式に影響する特定の攻撃を防ぎます)
  • 改ざん検出機能内蔵 — 転送中にデータが変更されると復号が失敗します
  • Android 側:Google Tink を使用
  • Web 側:@noble/ciphers(十分に監査された JavaScript 暗号ライブラリ)を使用
3

デジタル署名(Ed25519)——デバイス間通信

2 台の PlainApp デバイスが通信するとき(例:スマートフォン同士のチャット)、暗号化だけでは不十分です——各デバイスはメッセージが本当に相手のデバイスから来たものであり、偽造されていないことを検証する必要があります。

タイムスタンプ

受信側デバイスは送信者の公開鍵で署名を検証し、タイムスタンプが 5 分以上前のリクエストを拒否します。これにより偽造とリプレイ攻撃の両方を防止します。

4

安全なデバイスペアリング(ECDH 鍵交換)

2 台の PlainApp デバイスがペアリングするとき(例:スマートフォン 2 台)、共有暗号鍵が必要になります。しかし、鍵をネットワーク経由で送信しては意味がありません。

PlainApp はこの問題を ECDH(Elliptic Curve Diffie-Hellman)鍵交換で解決します — TLS、Apple の Secure Enclave、WebAuthn で使われているのと同じ数学的手法です:

  1. 1各デバイスが鍵ペア(公開鍵 + 秘密鍵)を生成します
  2. 2公開鍵のみを交換します
  3. 3各デバイスが自分の秘密鍵と相手の公開鍵を組み合わせます
  4. 4双方が同じ共有シークレットに到達します — ネットワーク上に共有シークレットが流れることはありません
ECDH Pairing Flow
5

暗号化された URL — ファイルパスの隠蔽

多くの人が気づかない点があります。URL パスも情報を漏洩するのです。

ファイルをダウンロードする際、URL はサーバーにどのファイルが必要かを伝えます。多くのアプリでは URL が以下のように表示されます:

/fs?path=/sdcard/DCIM/Camera/photo_2024.jpg

通信を傍受している人(またはブラウザの履歴を見た人)は、アクセスしたファイルとスマートフォンのフォルダ構成を正確に把握できます。

PlainApp は URL 内のファイルパスを暗号化します:

/fs?id=AxK9f2mQ7vR3xP8nWz...

id パラメータは、URL Token と呼ばれるランダムキーを使って XChaCha20-Poly1305 で暗号化されたファイルパスです。デフォルトではこのキーは永続的で、アプリを再起動しても変わりません。そのため、共有したリンクはそのまま使い続けられます。キーなしでは、実際のパスを推測したり、ファイルを列挙したり、ダウンロード URL を作成したりすることはできません。

URL Encryption Comparison
6

自己署名証明書による HTTPS

PlainApp はスマートフォン上で自己署名の TLS 証明書を生成します。これにより暗号化された HTTPS トンネルが作られます — 銀行や Web サイトが使用しているのと同じ技術です。

証明書の仕様:

  • ECDSA(P-256 曲線を使用、主要な Web サイトと同等です)
  • SHA256 署名
  • アプリのプライベートディレクトリに保存されます

アプリケーション層の XChaCha20 暗号化と組み合わせることで、2 つの独立した暗号化レイヤーが実現されます。一方を突破しても、もう一方を突破しなければ意味がありません。

7

ログイン保護

PlainApp はパスワード推測を防ぐためにログイン試行回数を制限しています:

  • IP アドレスあたり 60 秒間に 5 回まで
  • 制限を超えると接続が拒否されます
  • 古いレートリミットの記録は自動的にクリーンアップされます

HTTP と HTTPS:正直な比較

PlainApp は HTTP モードと HTTPS モードの両方を提供しています。その違いを正直に解説します:

HTTP モードHTTPS モード
ファイルパス URL暗号化済み(XChaCha20)暗号化済み(XChaCha20)
API 呼び出し暗号化済み(XChaCha20)暗号化済み(XChaCha20 + TLS)
ファイルダウンロード転送中は暗号化されませんTLS により暗号化済み
対象ユーザー初心者向け(ブラウザの SSL 警告なし)プライバシーを重視するユーザー向け

どちらのモードでも API 呼び出しは XChaCha20-Poly1305 で暗号化されます — HTTP でも HTTPS でも、SMS・連絡先・その他のデータは常に暗号化されています。

HTTP モードが存在するのは、自己署名証明書がブラウザに「この接続ではプライバシーが保護されません」という警告を表示させるためです。技術に詳しくないユーザーにとって、この警告は混乱を招きます。HTTP ならこの問題を避けられます。

ただし、HTTP モードではファイル転送が暗号化されません。共有ネットワークや公衆ネットワークでは、必ず HTTPS を使用してください。

推奨:可能な限り HTTPS を使用してください。ブラウザの自己署名証明書の警告は、ローカルネットワークアプリでは正常かつ想定どおりのものです。

8

サプライチェーンセキュリティ — 依存関係を減らしてリスクを低減

多くのユーザーが見落としているセキュリティの脅威があります。それがサプライチェーン攻撃です。アプリが何百ものサードパーティライブラリを使用していると、そのどれか一つが侵害される可能性があります — データの窃取、暗号通貨のマイニング、バックドアの設置といった悪意のあるコードが注入されるかもしれません。

これは JavaScript エコシステムにおいて特に危険です。近年、event-stream、ua-parser-js、colors といった人気の npm パッケージが乗っ取られ、何百万ものプロジェクトに悪意のあるコードが注入されました。スマートフォン管理アプリの Web UI が何百もの JS パッケージを読み込んでいる場合、それぞれが潜在的な攻撃経路になります。

PlainApp は意図的なアプローチをとっています:依存関係を可能な限り少なくし、合理的な場合には独自コードを実装します。

Android アプリ(plain-app)

  • DI フレームワーク不使用(Hilt も Dagger もなし)— シンプルなシングルトンを使用しています
  • 暗号処理は、Google Tink、Bouncy Castle、組み込みの Java Cryptography Extension の 3 つの著名なライブラリのみで実現しています
  • サーバーは Ktor(JetBrains 公式の Kotlin フレームワーク)で動作します — 不明瞭なサードパーティのサーバーライブラリは使用していません

Web UI(plain-desktop)

ランタイム依存関係はわずか 28 個 — 一般的な Web アプリと比べてはるかに少ないです。通常であれば npm パッケージが必要になるいくつかの機能を、ゼロから構築しています:

機能一般的なアプリPlainApp
通知音howler.js / tone.js独自の Web Audio API シンセサイザー
UUID 生成uuid npm パッケージ独自の RFC 4122 実装
ファイルアップロードuppy / axios独自のチャンク分割アップロードとキュー
WebRTC ビデオTwilio / Daily.co SDK独自の PeerConnection コード
HTTP クライアントaxios / kyブラウザネイティブの fetch

Web 側の暗号処理には @noble/ciphers を使用しています — 十分に監査された、依存関係ゼロの JavaScript 暗号ライブラリであり、大規模で肥大化した代替ライブラリの代わりとなります。

なぜこれが重要なのか

追加するすべての依存関係は、自分がコントロールできないコードです。PlainApp のアプローチがもたらす効果:

  • 悪意のあるコードが潜む場所が少なくなります
  • 攻撃対象が縮小されます
  • 監査が容易です(コードベース全体がオープンソースです)
  • 放棄された、または乗っ取られた npm パッケージのリスクがありません

多くの競合アプリが見落としていること

特定のアプリ名を挙げるものではありません。このカテゴリで共通して見られるパターンについてです:

セキュリティの観点PlainApp競合アプリに多い状況
API 通信暗号化済み(XChaCha20)HTTP でも HTTPS でもHTTP 上の平文 JSON
WebSocket 通信暗号化バイナリフレーム(XChaCha20)プレーンテキスト JSON または WebSocket なし
認証トークンの扱い暗号化キーとして使用、ヘッダーには含めないHTTP ヘッダーで送信(漏洩しやすい)
ファイル URL暗号化されたパス ID平文のパスが露出
鍵交換ECDH(P-256)なし
リクエスト署名Ed25519(デバイス間のみ)なし
リプレイ防止30 秒 + nonce(Web)、5 分 + 署名(デバイス間)なし
ログイン保護レート制限 + 二要素確認無制限
データ経路100% ローカル、クラウド不使用クラウド経由のものもあります
依存関係最小限の著名なライブラリ何百もの npm パッケージ
ソースコードオープンソース(GPL-3.0)ほとんどがクローズドソース

どのアプリでも簡単にチェックできます:アプリの使用中に Chrome DevTools(F12)→ Network タブを開いてください。API レスポンスが JSON で読めるなら、そのアプリには暗号化がありません。

ご自身で確認してください

PlainApp は完全なオープンソースです。この記事のすべての主張はコードで検証できます。

github.com/plainhub/plain-app (GPL-3.0)
検証可能なリリース完全性

自動化・追跡可能・改ざん耐性のあるリリースパイプライン

すべてのインストールパッケージは GitHub と F-Droid の基盤で自動ビルドされます。ビルドは追跡可能で安全、手動介入の痕跡を残しません。PlainApp は検証可能ビルド(SLSA)と VirusTotal スキャン済みリリースの両方を提供する数少ない Android アプリです。

GitHub と F-Droid での自動ビルド

リリース成果物はローカル手動パッケージングではなく CI パイプラインで生成されます。各成果物はソースコミットと再現可能ビルドワークフローまで追跡できます。

SLSA Provenance(レベル3)+ VirusTotal スキャン

各リリースには SLSA provenance 証明と VirusTotal スキャン結果が含まれ、サプライチェーン監査性が向上し、インストール前の完全性検証が可能になります。

よくある質問

HTTP モードでも PlainApp は本当に暗号化されていますか?

はい。すべての API 呼び出し(SMS、連絡先、ファイル一覧など)は HTTP モードでも HTTPS モードでも XChaCha20-Poly1305 で暗号化されます。HTTP モードで暗号化されないのはファイルダウンロードのみです。完全な保護が必要な場合は HTTPS を使用してください。

ブラウザにセキュリティ警告が表示されるのはなぜですか?

PlainApp は暗号化のために自己署名の TLS 証明書を使用しています。公的な認証局が発行した証明書ではないため、ブラウザが警告を表示します。これはローカルネットワークアプリでは正常かつ想定どおりの動作です。「詳細設定」→「続行」をクリックして進んでください。

同じ Wi-Fi 上の人に自分のデータが見られることはありますか?

PlainApp を使用していれば、見られることはありません。API 呼び出しは XChaCha20-Poly1305 で暗号化されており、HTTPS モードではファイル転送も TLS で暗号化されます。しかし多くの競合アプリでは、API 呼び出しが平文の JSON で送信されるため、見られる可能性があります。

PlainApp は VPN と比べてどうですか?

VPN はデバイスと VPN サーバー間の通信を暗号化します。PlainApp はローカルネットワーク上のスマートフォンとブラウザ間の通信を暗号化します。目的が異なります — PlainApp はローカルのデバイス管理を保護し、VPN はインターネット通信を保護します。

コードは本当にオープンソースですか?

はい。PlainApp は GPL-3.0 ライセンスで提供されています。完全なソースコードは github.com/plainhub/plain-app で公開されています。すべての暗号化実装を確認したり、ソースからビルドしたり、開発に貢献したりできます。

携帯電話の制御を取り戻しましょう。

クラウド仲介業者は存在しません。月額料金はかかりません。携帯電話とブラウザだけでOK。