🔐

(セキュリティ目的)(自分のアプリで)情報盗んで攻撃してみた(意外と漏れてた)

に公開

本記事はセキュリティ意識向上のための検証を目的としており、第三者への攻撃を推奨するものではありません

前回の記事では、私のアプリを仮想の環境で攻撃してみた。ふと思ったのは、実際にどんな手順で攻撃者は動いてくるのか、ということだ。セキュリティを考える上で、相手の立ち回りを把握できていれば守りやすくなると思った。そこで今回は、非エンジニアにもわかるように手口の一つをまとめてみた。

今回私が最も驚いたのは、かなり多くの情報(関数名、認証情報、データ等)が誰でも容易に手に入ってしまうということだ。バレることを前提に対策を取ることが大切になってくる。今回使ったのは mitmweb である。

傍受とは何か

例えば、悪意ある者が本物そっくりの郵便局を建てておく。そこにあなたが郵便物を持ち込む。悪意ある者はその中身を把握してから、本物の郵便局に提出する。こうすることで郵便物は目的の場所にしっかり届くため、あなたは郵便物の中身を見られたことに気づけない。これが今回の傍受の手口である。

実際も、スマホとサーバーの間でデータのやり取りが行われている。その間に立つことで、前述したデータをバレずに盗み取ることができるのである。しかも、間に立つのに特別な道具が必要なわけではない。今回も無料のツールのみで、数多のデータが傍受できてしまった。

実際に傍受してみた

傍受してみて、正直ぞっとした。今まで意識したこともなかったが、ここまで詳細に見えてしまうのか。

傍受で見えてしまった情報

① サーバーの地図

  • サーバーの所在(どのドメイン・どのクラウドを使っているか)
  • 呼び出している関数の名前(機能がそのまま推測できる命名だった)
  • 認証基盤への通信先と、そこに付いていた API キー

② 本人確認の鍵(最も危険)

  • 認証トークン(ログイン中の本人であることを証明する文字列)
  • このトークンはデコードするだけで中身が読め、そこから:
    • ユーザーの内部 ID
    • メールアドレス
    • メールが確認済みかどうか
    • ログイン方法(どの SNS 連携でログインしたか)
    • トークンの有効期限

③ アプリが送っている中身

  • どの操作を要求しているか(リクエストの本体パラメータ)
  • その操作に渡している値が、そのまま平文で(暗号化されず、読める文字のまま)

④ 端末・アプリの情報

  • アプリ名とバージョン
  • OS の種類とバージョン
  • 端末の機種
  • プッシュ通知の宛先トークン
  • 言語設定

⑤ 通信の状況

  • 通信の成否(成功か失敗か)
  • レスポンスのサイズ・所要時間
  • 同じ操作を何回繰り返したか

実際には、こんな形で表示される。

POST https://[リージョン]-[プロジェクトID].cloudfunctions.net/[課金を検証する関数]

content-type: application/json
authorization: Bearer eyJhbGci…        ← 本人確認の鍵(後述)
user-agent: [アプリ名]/[バージョン] iPhone/[OSバージョン] hw/[機種]
firebase-instance-id-token: …          ← プッシュ通知の宛先
accept-language: ja

{
  "data": {
    "serverVerificationData": "…",     ← 購入レシート
    "productID": "…"                   ← 購入した商品名
  }
}

とくに気になるのが authorization の一行。一見ただの長い文字列だが、これをデコードすると——

{
  "user_id": "…",
  "email": "…@…",                  ← メールアドレス
  "email_verified": true,
  "sign_in_provider": "apple.com",   ← ログイン方法
  "exp": …                           ← 有効期限
}

このように、本人のメールアドレスやログイン方法まで読めてしまう。「②本人確認の鍵」を最も危険と書いたのはこのためだ。

漏れた情報で何ができるのか

一番大事なのは、漏れ出た情報から何ができるのか、というところだと思う。

驚くことに、今回盗み取った情報を組み合わせるだけで、アプリを介さず、サーバーに直接「このデータを返せ」「書き換えろ」と要求できてしまう。しかもサーバーは、それを “正規の本人からの要求” だと信じて応じてしまう。なぜなら、③で触れた「本人確認の鍵」まで一緒に盗まれているからだ。サーバーには、本人と攻撃者を見分ける手段がない。

さっきの郵便局の例で言えば、こうなる。悪意ある者は、盗んだ “あなたの印鑑” を使って、あなた本人になりすまし、本物の郵便局に郵便物を出せてしまう。中身を覗かれただけでなく、あなたの名前で勝手に手紙を送られてしまうのだ。

ここでの肝は、今回傍受したデータは、私たちが何をしようとも隠せないということだ。アプリがサーバーと話す以上、その会話は外から見られる前提でしかない。つまり『情報はどうせバレる』という認識のもとで、私たちは対策を練る必要がある。

修正と確認

私は急いで、修正と確認を済ませた。手順については前回と重複するため割愛するが、考え方は一つだ。クライアントから送られてきた情報を鵜呑みにせず、サーバー側で必ず検証してから処理する。今回見つかった穴も、結局はサーバーがクライアントの言い分を信じすぎていたことが原因だった。

修正後、攻撃者と同じ手順でもう一度試してみたが、今度はきちんと弾かれた。もちろん、正規の操作は問題なく通ることも確認済みだ。

まとめ

今回の一連の流れから分かったことは、とんでもない量の情報が誰でも傍受できてしまうこと。また、それは避けようがないということである。これらのことから私たちがやるべきことは、クライアント側(情報を要求する側)を信用しないことだ。アプリの画面でどんな制限をかけても、見てきた通り通信は見られ、なりすまされる。だから守りは全部サーバー側に置く。思い返せば前回も、ログイン情報のみではなく、サーバー側のチェックを挟むことで対策を講じた。このことから、クライアントの外側で守る、というのが一つの答えになるかもしれない。

前回も書いたが、AI は動くことを優先してコードを書く。その分、今回のように悪意ある者が攻撃してきた場合という視点が抜けがちである。そのため今のところは、自分の手でもう一度確認しなくてはならない(将来的にはそこまで完璧に作ってくれるかもしれないが)。

情報が漏洩してからでは遅い。病気や特殊詐欺のように自分は大丈夫と思わず、今一度確認をしてみてほしい。

これからも AI で作った制作物のセキュリティについて書いていくので、よろしくお願いします。

Discussion