「他のアプリに乗っ取られてテレビを操作されないか」への回答。 結論から言うと、他アプリからの乗っ取りは塞いであるが、同じ Wi-Fi にいる人と 端末を手に取れる人は別の話で、そこは仕組み上どうにもならない部分がある。
| 経路 | 対策 |
|---|---|
| ブロードキャストを投げて送信させる | TvRemoteWidget は android:exported="false"。他アプリからは届かない |
こちらの PendingIntent を横取りして書き換える |
どれも FLAG_IMMUTABLE。受け取った側がフィールドを埋められない |
| 別ウィジェットのボタンを押させる | PendingIntent は requestCode + action + data + component で同一判定され、extras は無視される。extras だけで区別すると 2 つのウィジェットが同じ PendingIntent を共有してしまうため、requestCode = appWidgetId * MAX_SLOTS + slot と tvremocon://widget/<id>/slot/<n> の data URI の両方で区別している |
| デバッグ画面を開かせて任意のキーを送らせる | DebugActivity は exported="false"。パスワード入力欄があり全キーを送れる画面なので、他アプリから表示できてはいけない |
| 設定画面を任意の widgetId で開かせる | WidgetSetupActivity は APPWIDGET_CONFIGURE のため exported にせざるを得ない。そこで起動時に getAppWidgetIds() で自分のプロバイダの id か検証し、違えば即 finish() する |
- 生パスワードは保存しない。 設定画面で
authHashを導出したら破棄する authHashはパスワード相当(これがあればハブに認証できる)なので、平文保存はしない:- Android Keystore の鍵で AES-GCM 暗号化
noBackupFilesDirに保存(allowBackup=falseだけでは一部メーカー端末の端末間移行を止められないため)dataExtractionRules/backup_rulesでクラウドバックアップと端末間移行の両方から除外
- Keystore 鍵にユーザー認証を要求していない。ロック画面の上でウィジェットが動く必要があるため。
つまり端末のロックが破られた場合、
authHashは取り出されうる - 保存した資格情報を破棄するのは、その鍵ではもう復号できないと分かる場合だけ (GCM タグ不一致、鍵の無効化・消失)。Keystore の一時的な失敗や読み取り失敗では消さない。 以前は例外を区別せず消していたため、一過性の不調で再設定が必要になりえた
authHash/ パスワード / セッション Cookie はログに出さない(Cookie は有無だけ記録)
- KLAP v2 は AES-128-CBC + SHA256 署名で、中身は暗号化されている。HTTP なのは外側の枠だけ
- 応答の署名を検証している。 AES-CBC 自体は改ざんを検知しないので、
復号の前に
SHA256(署名鍵 || seq || 暗号文)を再計算して定数時間で比較する。 一致しなければ「結果不明」として扱い、再試行しない(要求自体は送信済みで、 かつ妨害している相手にもう一度機会を与えないため)。署名の偽造には資格情報由来の鍵が必要 - ただし
network_security_config.xmlは cleartext をアプリ全体で許可している。 domain-config はホスト名にしか効かず、ハブのアドレスは DHCP 次第で変わるため、XML では絞れない。 代わりにHubEndpointがコードで絞っている:- プライベート IPv4 リテラルのみ(10/8, 172.16/12, 192.168/16, 169.254/16)
- ポート 80 固定
- パスは
/app/{handshake1,handshake2,request}のみ - リダイレクトを追わない(
followRedirects(false))
- 通信先は Wi-Fi の
Networkに固定。モバイル回線へ漏れない - LAN の自動探索は 10 分に 1 回まで。 探索はサブネットの全アドレスに TCP 接続し、 ポート 80 が開いている相手に handshake を投げるので、自宅以外のネットワークで 押下のたびに実行されると迷惑になる。設定画面の手動探索は制限しない
- 同じ LAN にいて TP-Link アカウントを知っている人は、このアプリと同じことができる。 これはハブ側の認証の話で、アプリでは変えられない。KLAP は LAN 内の誰でも ハンドシェイクを試せる(資格情報が合わなければそこで止まる)
- 端末のロックを破られた場合、ウィジェットのボタンは押せるし
authHashも取り出されうる。 ウィジェットがロック画面上で動く以上、これは設計上のトレードオフ - TP-Link の非公式 API を使っている。ファームウェア更新で挙動が変わりうる
- ハブ自体の脆弱性はこのアプリの範囲外
- 自動再送しない。 アプリ層・KLAP 層・HTTP 層のそれぞれで抑止している。 応答が失われた場合は「失敗」ではなく「結果不明」と表示する。 勝手に再送すると音量が 2 段階上がるなど、物理的な影響が二重になる
- 期限切れの操作は捨てる。 連打で詰まった古いタップを後から実行しない
- ブロードキャストを長く保持しない。 Android は同じ受信側へのブロードキャストを直列に配信するため、 待機のために保持すると後続のタップがその裏で滞留する。休止に戻す待機は保持せずに行う