コース目次 / 第4章

直す — 秘密を抜き、マニフェストを締める

ハードコードされた秘密を除去し、allowBackup/exportedを締め、usesCleartextTrafficを外して再ビルドします。jadx/apktoolで直った状態を再検証します。

第4章 / 全6章目安 約10分この章のゴール: 4つの穴を直し、再ビルド・再検証できるようになる

4つの穴を、この章で一気に直します。原則は、これまでと同じ——事実(秘密)はクライアントに置かない、既定は最も締まった設定に。

直し1 — 秘密を、コードから抜く

MainActivity.smali から、API_KEY の行を削除します。

.class public Lcom/example/vulnnotes/MainActivity;
.super Landroid/app/Activity;

.method public constructor <init>()V
    .locals 0
    invoke-direct {p0}, Landroid/app/Activity;-><init>()V
    return-void
.end method

直した先の設計は、「アプリの起動時に、サーバから必要なトークンを取得する」形です(sec-auth のセッション管理と同じ発想——アプリが持つのは、都度取得する短命な認証情報であって、埋め込まれた恒久的な秘密鍵ではありません)。APIキーのような恒久的な秘密は、そもそもクライアントのバイナリに含めないのが本筋です。

直し2〜4 — マニフェストを、締める

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.vulnnotes">
    <uses-permission android:name="android.permission.INTERNET" />
    <application
        android:label="VulnNotes"
        android:allowBackup="false">
        <activity android:name=".MainActivity" android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".AdminActivity" android:exported="false" />
    </application>
</manifest>

allowBackup=“false” — バックアップ経由の抽出を禁じる。
usesCleartextTraffic の指定を削除 — 指定しなければ、Android の既定(平文禁止)に従う。「緩めない」のがいちばん簡単な直し方です。
AdminActivity は exported=“false” — 起動画面ではないので、他アプリから直接起動される理由がありません。もし将来、他アプリと連携する正当な理由ができたら、そのときは限定した権限(android:permission)を要求する形で、慎重に開けます。

再ビルドして、再検証する

apktool b vulnnotes -o vulnnotes.apk
jarsigner -keystore debug.keystore -storepass android vulnnotes.apk debugkey

秘密が消えたか、jadx で確認します。

jadx -d out -f vulnnotes.apk
cat out/sources/com/example/vulnnotes/MainActivity.java
package com.example.vulnnotes;
import android.app.Activity;
public class MainActivity extends Activity {
}

マニフェストが締まったか、apktool で確認します。

apktool d -f -o decompiled vulnnotes.apk
cat decompiled/AndroidManifest.xml
<application android:label="VulnNotes" android:allowBackup="false">
    <activity android:name=".MainActivity" android:exported="true">
        ...
    </activity>
    <activity android:name=".AdminActivity" android:exported="false" />
</application>

秘密は消え、allowBackup は false、usesCleartextTraffic の記述自体が無くなり(既定の安全側)、AdminActivity は exported=“false” になりました。これで、この章の4つの穴はすべて塞がっています。MainActivity の exported=“true” は、起動画面として必要な設定なので、そのままです——「すべて閉じる」のではなく、「開ける理由があるものだけ、開けたままにする」のが正しい締め方です。

持ち帰る一言

開ける理由があるものだけ、開けたままにする。 秘密はクライアントから抜き、バックアップと平文通信は既定で禁じ、exportedは本当に必要なものだけ。再ビルドして、逆コンパイルで直ったことを目で確かめる——これも旗艦コースからの「攻撃→修正→再検証」でした。次はまとめて、静的解析の限界と、この先の道を確認します。

こうなっていればOK

卒業まであと1章です。

この章はまだ完了していません。