1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/wizardforcel-android-app-sec-guidebook

Клонировать/Скачать
4.1.1.4.md 13 КБ
Копировать Редактировать Web IDE Исходные данные Просмотреть построчно История
gitlife-traslator Отправлено 27.11.2024 20:24 c13bfb7

Создание/использование внутренней активности

Внутренняя активность — это активность, которая предназначена для использования только внутри приложения и не может быть использована другими приложениями. Они используются в приложениях для внутренней разработки, чтобы безопасно обмениваться информацией и функциями.

Сторонние приложения могут считывать намерения, которые запускают активности. Поэтому, если вы помещаете чувствительную информацию в намерение, которое запускает активность, необходимо принять меры, чтобы гарантировать, что она не будет прочитана злоумышленниками.

Ниже приведён пример кода для создания внутренней активности.

Основные моменты (создание активности):

  1. Определить внутреннее разрешение на подпись.
  2. Не указывать taskAffinity.
  3. Не указывать launchMode.
  4. Требуется внутреннее разрешение на подпись.
  5. Не определять фильтр намерений и явно установить экспортируемый атрибут в true.
  6. Убедиться, что внутреннее разрешение на подпись определено внутренним приложением.
  7. Тщательно и безопасно обрабатывать полученное намерение, даже если оно было отправлено внутренним приложением.
  8. Поскольку запрашивающее приложение является внутренним, можно вернуть чувствительную информацию.
  9. При экспорте APK используйте тот же ключ разработчика, который использовался для подписи целевого приложения.

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="org.jssec.android.activity.inhouseactivity" >

    <!-- *** POINT 1 *** Define an in-house signature permission -->
    <permission
        android:name="org.jssec.android.activity.inhouseactivity.MY_PERMISSION"
        android:protectionLevel="signature" />

    <application
        android:allowBackup="false"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >

        <!-- In-house Activity -->
        <!-- *** POINT 2 *** Do not specify taskAffinity -->
        <!-- *** POINT 3 *** Do not specify launchMode -->
        <!-- *** POINT 4 *** Require the in-house signature permission -->
        <!-- *** POINT 5 *** Do not define the intent filter and explicitly set the exported attribute to
true -->
        <activity
            android:name="org.jssec.android.activity.inhouseactivity.InhouseActivity"
            android:exported="true"
            android:permission="org.jssec.android.activity.inhouseactivity.MY_PERMISSION" />
    </application>
</manifest>

InhouseActivity.java

package org.jssec.android.activity.inhouseactivity;

import org.jssec.android.shared.SigPerm;
import org.jssec.android.shared.Utils;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

public class InhouseActivity extends Activity {

    // In-house Signature Permission
    private static final String MY_PERMISSION = "org.jssec.android.activity.inhouseactivity.MY_PERMISSION";
    // In-house certificate hash value
    private static String sMyCertHash = null;

    private static String myCertHash(Context context) {
        if (sMyCertHash == null) {
            if (Utils.isDebuggable(context)) {
                // Certificate hash value of "androiddebugkey" in the debug.keystore.
                sMyCertHash = "0EFB7236 328348A9 89718BAD DF57F544 D5CCB4AE B9DB34BC 1E29DD26 F77C8255";
            } else {
                // Certificate hash value of "my company key" in the keystore.
                sMyCertHash = "D397D343 A5CBC10F 4EDDEB7C A10062DE 5690984F 1FB9E88B D7B3A7C2 42E142CA";
            }
        }
        return sMyCertHash;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        // *** POINT 6 *** Verify that the in-house signature permission is defined by an in-house application.
        if (!SigPerm.test(this, MY_PERMISSION, myCertHash(this))) {
            Toast.makeText(this, "The in-house signature permission is not declared by in-house application.",
            Toast.LENGTH_LONG).show();
            finish();
            return;
        }

        // *** POINT 7 *** Handle the received intent carefully and securely, even though the intent was sent from an in-house application.
        // Omitted, since this is a sample. Please refer to "3.2 Handling Input Data Carefully and Securely."
        String param = getIntent().getStringExtra("PARAM");
        Toast.makeText(this, String.format("Received param: ¥"%s¥"", param), Toast.LENGTH_LONG).show();
    }

    public void onReturnResultClick(View view) {
        // *** POINT 8 *** Sensitive information can be returned since the requesting application is inhouse.
        Intent intent = new Intent();
        intent.putExtra("RESULT", "Sensitive Info");
        setResult(RESULT_OK, intent);
        finish();
    }
}

SigPerm.java InhouseUserActivity.java

package org.jssec.android.activity.inhouseuser;

import org.jssec.android.shared.PkgCert;
import org.jssec.android.shared.SigPerm;
import org.jssec.android.shared.Utils;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

public class InhouseUserActivity extends Activity {

    // Target Activity information
    private static final String TARGET_PACKAGE = "org.jssec.android.activity.inhouseactivity";
    private static final String TARGET_ACTIVITY = "org.jssec.android.activity.inhouseactivity.InhouseActivity";
    // In-house Signature Permission
    private static final String MY_PERMISSION = "org.jssec.android.activity.inhouseactivity.MY_PERMISSION";
    // In-house certificate hash value
    private static String sMyCertHash = null;

    private static String myCertHash(Context context) {
        if (sMyCertHash == null) {
            if (Utils.isDebuggable(context)) {
                // Certificate hash value of "androiddebugkey" in the debug.keystore.
                sMyCertHash = "0EFB7236 328348A9 89718BAD DF57F544 D5CCB4AE B9DB34BC 1E29DD26 F77C8255";
            } else {
                // Certificate hash value of "my company key" in the keystore.
                sMyCertHash = "D397D343 A5CBC10F 4EDDEB7C A10062DE 5690984F 1FB9E88B D7B3A7C2 42E142CA";
            }
        }
        return sMyCertHash;
    }

    private static final int REQUEST_CODE = 1;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }

    public void onUseActivityClick(View view) {
        // *** POINT 11 *** Verify that the in-house signature permission is defined by an in-house application.
        if (!SigPerm.test(this, MY_PERMISSION, myCertHash(this))) {
            Toast.makeText(this, "The in-house signature permission is not declared by in-house application.",
            Toast.LENGTH_LONG).show();
            return;
        }
        // ** POINT 12 *** Verify that the destination application is signed with the in-house certificate.
        if (!PkgCert.test(this, TARGET_PACKAGE, myCertHash(this))) {
            Toast.makeText(this, "Target application is not an in-house application.", Toast.LENGTH_LONG).show();
            return;
        }
        try {
            Intent intent = new Intent();
            // *** POINT 13 *** Sensitive information can be sent only by putExtra() since the destination application is in-house.
            intent.putExtra("PARAM", "Sensitive Info");

            // *** POINT 14 *** Use explicit intents to call an In-house Activity.
            intent.setClassName(TARGET_PACKAGE, TARGET_ACTIVITY);
            startActivityForResult(intent, REQUEST_CODE);
        } catch (ActivityNotFoundException e) {
            Toast.makeText(this, "Target activity not found.", Toast.LENGTH_LONG).show();
        }
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (resultCode != RESULT_OK) return;
        switch (requestCode) {
            case REQUEST_CODE:
                String result = data.getStringExtra("RESULT");
                // *** POINT 15 *** Handle the received data carefully and securely,
                // even though the data came from an in-house application.
                // Omitted, since this is a sample. Please refer to "3.2 Handling".
        }
}
``` **SigPerm.java**

package org.jssec.android.shared;

import android.content.Context; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.PermissionInfo;

public class SigPerm { public static boolean test(Context ctx, String sigPermName, String correctHash) { if (correctHash == null) return false; correctHash = correctHash.replaceAll(" ", ""); return correctHash.equals(hash(ctx, sigPermName)); }

public static String hash(Context ctx, String sigPermName) {
    if (sigPermName == null) return null;
    try {
        // Получаем имя пакета приложения, которое объявляет разрешение с именем sigPermName.
        PackageManager pm = ctx.getPackageManager();
        PermissionInfo pi;
        pi = pm.getPermissionInfo(sigPermName, PackageManager.GET_META_DATA);
        String pkgname = pi.packageName;
        // Завершаем работу с ошибкой, если разрешение с именем sigPermName не является разрешением подписи
        if (pi.protectionLevel != PermissionInfo.PROTECTION_SIGNATURE) return null;
        // Возвращаем значение хэша сертификата приложения, которое заявляет разрешение с именем sigPermName.
        return PkgCert.hash(ctx, pkgname);
    } catch (NameNotFoundException e) {
        return null;
    }
}

}


**PkgCert.java**

package org.jssec.android.shared;

import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import android.content.Context; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.Signature;

public class PkgCert { public static boolean test(Context ctx, String pkgname, String correctHash) { if (correctHash == null) return false; correctHash = correctHash.replaceAll(" ", ""); return correctHash.equals(hash(ctx, pkgname)); }

public static String hash(Context ctx, String pkgname) {
    if (pkgname == null) return null;
    try {
        PackageManager pm = ctx.getPackageManager();
        PackageInfo pkginfo = pm.getPackageInfo(pkgname, PackageManager.GET_SIGNATURES);
        if (pkginfo.signatures.length != 1) return null; // Не будет обрабатывать несколько подписей.
        Signature sig = pkginfo.signatures[0];
        byte[] cert = sig.toByteArray();
        byte[] sha256 = computeSha256(cert);
        return byte2hex(sha256);
    } catch (NameNotFoundException e) {
        return null;
    }
}

private static byte[] computeSha256(byte[] data) {
    try {
        return MessageDigest.getInstance("SHA-256").digest(data);
    } catch (NoSuchAlgorithmException e) {
        return null;
    }
}

private static String byte2hex(byte[] data) {
    if (data == null) return null;
    final StringBuilder hexadecimal = new StringBuilder();
    for (final byte b : data) {
        hexadecimal.append(String.format("%02X", b));
    }
    return hexadecimal.toString();
}

}


*Надо отметить 16: при экспорте APK используйте тот же ключ разработчика для подписания APK.*

Опубликовать ( 0 )

Вы можете оставить комментарий после Вход в систему

1
https://api.gitlife.ru/oschina-mirror/wizardforcel-android-app-sec-guidebook.git
git@api.gitlife.ru:oschina-mirror/wizardforcel-android-app-sec-guidebook.git
oschina-mirror
wizardforcel-android-app-sec-guidebook
wizardforcel-android-app-sec-guidebook
master