1. 本app内部使用的activity一定要设置为非公开

创新互联-专业网站定制、快速模板网站建设、高性价比嘉定网站开发、企业建站全套包干低至880元,成熟完善的模板库,直接使用。一站式嘉定网站制作公司更省心,省钱,快速模板网站建设找我们,业务覆盖嘉定地区。费用合理售后完善,十多年实体公司更值得信赖。
不准备对外公开的activity一定要设置为非公开,以防止被人非法调用
- android:name=".PrivateActivity"
 - android:label="@string/app_name"
 - android:exported="false" />
 - android:name=".PrivateActivity"
 - android:label="@string/app_name"
 - android:exported="false" />
 
同时,一定要注意的是, 非公开的Activity不能设置intent-filter
因为,如果假设在同一机器上,有另外一个app有同样的intent-filter的话, 调用该Activity的intent会唤醒android的选择画面, 让你选择使用那个app接受该intent。这样就会事实上绕过了非公开的设置。
2. 不要指定taskAffinity
Android中的activity全都归属于task管理 , 简单说来task是一种stack的数据结构, 先入后出。
一般来说, 如果不指明归属于什么task, 同一个app内部的所有Activity都会存续在一个task中,task的名字就是app的packageName。
因为在同一个andorid设备中,不会有两个同packageName的app存在,所以能保证Activity不被攻击。
但是如果你指明taskAffinity,比如如下
- [html]
 - android:taskAffinity="com.winuxxan.task"
 - android:label="@string/app_name">
 - android:taskAffinity="com.winuxxan.task"
 - android:label="@string/app_name">
 
那此时,恶意软件中的Activity如果也声明为同样的taskAffinity,那他的Activity就会启动到你的task中,就会有机会拿到你的intent
3. 不要指定LaunchMode(默认standard模式)
Android中Activity的LaunchMode分成 以下四种
Standard: 这种方式打开的Activity不会被当作rootActivity,会生成一个新的Activity的instance,会和打开者在同一个task内
singleTop: 和standard基本一样,唯一的区别在于如果当前task第一个Activity就是该Activity的话,就不会生成新的instance
singleTask:系统会创建一个新task(如果没有启动应用)和一个activity新实例在新task根部,然后,如果activity实例已经存在单独的task中,系统会调用已经存在activity的 onNewIntent()方法,而不是存在新实例,仅有一个activity实例同时存在。
singleInstance: 和singleTask相似,除了系统不会让其他的activities运行在所有持有的task实例中,这个activity是独立的,并且task中的成员只有它,任何其他activities运行这个activity都将打开一个独立的task。
所有发送给root Activity(根Activiy)的intent都会在android中留下履历。所以一般来说严禁用singleTask或者singleInstance来启动画面。
然而,即使用了standard来打开画面,也可能会出问题,比如如果调用者的Activity是用singleInstance模式打开,即使用standard模式打开被调用Activity,因为调用者的Activitytask是不能有其他task的, 所以android会被迫生成一个新的task,并且把被调用者塞进去,最后被调用者就成了rootActivity。
程序如下:
- AndroidManifest.xml
 - [html]
 - package="org.jssec.android.activity.privateactivity"
 - android:versionCode="1"
 - android:versionName="1.0" >
 - android:icon="@drawable/ic_launcher"
 - android:label="@string/app_name" >
 - android:name=".PrivateUserActivity"
 - android:label="@string/app_name"
 - android:launchMode="singleInstance" >
 - android:name=".PrivateActivity"
 - android:label="@string/app_name"
 - android:exported="false" />
 - package="org.jssec.android.activity.privateactivity"
 - android:versionCode="1"
 - android:versionName="1.0" >
 - android:icon="@drawable/ic_launcher"
 - android:label="@string/app_name" >
 - android:name=".PrivateUserActivity"
 - android:label="@string/app_name"
 - android:launchMode="singleInstance" >
 - android:name=".PrivateActivity"
 - android:label="@string/app_name"
 - android:exported="false" />
 
非公开Activity的代码如下:
- [java]
 - package org.jssec.android.activity.privateactivity;
 - import android.app.Activity;
 - import android.content.Intent;
 - import android.os.Bundle;
 - import android.view.View;
 - import android.widget.Toast;
 - public class PrivateActivity extends Activity {
 - @Override
 - public void onCreate(Bundle savedInstanceState) {
 - super.onCreate(savedInstanceState);
 - setContentView(R.layout.private_activity);
 - String param = getIntent().getStringExtra("PARAM");
 - Toast.makeText(this, String.format("「%s」取得。", param),
 - Toast.LENGTH_LONG).show();
 - }
 - public void onReturnResultClick(View view) {
 - Intent intent = new Intent();
 - intent.putExtra("RESULT", 机密数据");
 - setResult(RESULT_OK, intent);
 - finish();
 - }
 - }
 - package org.jssec.android.activity.privateactivity;
 - import android.app.Activity;
 - import android.content.Intent;
 - import android.os.Bundle;
 - import android.view.View;
 - import android.widget.Toast;
 - public class PrivateActivity extends Activity {
 - @Override
 - public void onCreate(Bundle savedInstanceState) {
 - super.onCreate(savedInstanceState);
 - setContentView(R.layout.private_activity);
 - String param = getIntent().getStringExtra("PARAM");
 - Toast.makeText(this, String.format("「%s」取得。", param),
 - Toast.LENGTH_LONG).show();
 - }
 - public void onReturnResultClick(View view) {
 - Intent intent = new Intent();
 - intent.putExtra("RESULT", 机密数据");
 - setResult(RESULT_OK, intent);
 - finish();
 - }
 - }
 
调用非公开Activity者,以standard模式打开
- [java]
 - package org.jssec.android.activity.privateactivity;
 - import android.app.Activity;
 - import android.content.Intent;
 - import android.os.Bundle;
 - import android.view.View;
 - import android.widget.Toast;
 - public class PrivateUserActivity extends Activity {
 - private static final int REQUEST_CODE = 1;
 - @Override
 - public void onCreate(Bundle savedInstanceState) {
 - super.onCreate(savedInstanceState);
 - setContentView(R.layout.user_activity);
 - }
 - public void onUseActivityClick(View view) {
 - // 用standard模式启动非公开Activity
 - Intent intent = new Intent();
 - intent.setClass(this, PrivateActivity.class);
 - intent.putExtra("PARAM", "机密数据");
 - startActivityForResult(intent, REQUEST_CODE);
 - }
 - @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");
 - break;
 - }
 - }
 - }
 - package org.jssec.android.activity.privateactivity;
 - import android.app.Activity;
 - import android.content.Intent;
 - import android.os.Bundle;
 - import android.view.View;
 - import android.widget.Toast;
 - public class PrivateUserActivity extends Activity {
 - private static final int REQUEST_CODE = 1;
 - @Override
 - public void onCreate(Bundle savedInstanceState) {
 - super.onCreate(savedInstanceState);
 - setContentView(R.layout.user_activity);
 - }
 - public void onUseActivityClick(View view) {
 - // 用standard模式启动非公开Activity
 - Intent intent = new Intent();
 - intent.setClass(this, PrivateActivity.class);
 - intent.putExtra("PARAM", "机密数据");
 - startActivityForResult(intent, REQUEST_CODE);
 - }
 - @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");
 - break;
 - }
 - }
 - }
 
4. 发给Activity的intent不要设定为FLAG_ACTIVITY_NEW_TASK
就算上面的Activity的lauchMode设置完善了, 在打开intent的时候还是能指定打开模式。
比如在intent中指明用FLAG_ACTIVITY_NEW_TASK模式的话,发现该activity不存在的话,就会强制新建一个task。如果同时设置了FLAG_ACTIVITY_MULTIPLE_TASK+ FLAG_ACTIVITY_NEW_TASK,就无论如何都会生成新的task,该Activity就会变成rootActiviy,并且intent会被留成履历
5. Intent中数据的加密
Activity中数据的传递都依靠intent, 很容易被攻击, 所以 就算同一个app内部传递数据, 最好还是要加密, 加密算法很多
6. 明确ActivityName发送Intent
明确Activity发送Intent,能够避免被恶意软件截取。
同一app内部的发送
- [java]
 - Intent intent = new Intent(this, PictureActivity.class);
 - intent.putExtra("BARCODE", barcode);
 - startActivity(intent);
 - Intent intent = new Intent(this, PictureActivity.class);
 - intent.putExtra("BARCODE", barcode);
 - startActivity(intent);
 - 不同app内部的发送
 - [java]
 - Intent intent = new Intent();
 - intent.setClassName(
 - "org.jssec.android.activity.publicactivity",
 - "org.jssec.android.activity.publicactivity.PublicActivity");
 - startActivity(intent);
 - Intent intent = new Intent();
 - intent.setClassName(
 - "org.jssec.android.activity.publicactivity",
 - "org.jssec.android.activity.publicactivity.PublicActivity");
 - startActivity(intent);
 
但是,要注意的是!
不是指明了packageName和ActivityName就能避免所有的问题,
如果有一个恶意软件故意做成和你发送目标同packageName, 同ActivityName, 此时的intent就会被截取
7. 跨app接受Intent时,要明确对方的身份
接受到别的app发来的intent时,要能确定对方的身份。
一个好方法是比对对方的app的hashcode。
当前,前提是调用者要用startActivityForResult(),因为只有这个方法,被调用者才能得到调用者的packageName
代码如下:
被调用的Activity
- [java]
 - package org.jssec.android.activity.exclusiveactivity;
 - import org.jssec.android.shared.PkgCertWhitelists;
 - 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 ExclusiveActivity extends Activity {
 - // hashcode的白名单
 - private static PkgCertWhitelists sWhitelists = null;
 - private static void buildWhitelists(Context context) {
 - boolean isdebug = Utils.isDebuggable(context);
 - sWhitelists = new PkgCertWhitelists();
 - sWhitelists
 - .add("org.jssec.android.activity.exclusiveuser", isdebug ?
 - "0EFB7236 328348A9 89718BAD DF57F544 D5CCB4AE B9DB34BC 1E29DD26 F77C8255"
 - :
 - "1F039BB5 7861C27A 3916C778 8E78CE00 690B3974 3EB8259F E2627B8D 4C0EC35A");
 - }
 - private static boolean checkPartner(Context context, String pkgname) {
 - if (sWhitelists == null)
 - buildWhitelists(context);
 - return sWhitelists.test(context, pkgname);
 - }
 - @Override
 - public void onCreate(Bundle savedInstanceState) {
 - super.onCreate(savedInstanceState);
 - setContentView(R.layout.main);
 - // check白名单
 - if (!checkPartner(this, getCallingPackage())) {
 - Toast.makeText(this, "不是白名单内部的。", Toast.LENGTH_LONG).show();
 - finish();
 - return;
 - }
 - }
 - public void onReturnResultClick(View view) {
 - Intent intent = new Intent();
 - intent.putExtra("RESULT", "机密数据");
 - setResult(RESULT_OK, intent);
 - finish();
 - }
 - }
 - package org.jssec.android.activity.exclusiveactivity;
 - import org.jssec.android.shared.PkgCertWhitelists;
 - 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 ExclusiveActivity extends Activity {
 - // hashcode的白名单
 - private static PkgCertWhitelists sWhitelists = null;
 - private static void buildWhitelists(Context context) {
 - boolean isdebug = Utils.isDebuggable(context);
 - sWhitelists = new PkgCertWhitelists();
 - sWhitelists
 - .add("org.jssec.android.activity.exclusiveuser", isdebug ?
 - "0EFB7236 328348A9 89718BAD DF57F544 D5CCB4AE B9DB34BC 1E29DD26 F77C8255"
 - :
 - "1F039BB5 7861C27A 3916C778 8E78CE00 690B3974 3EB8259F E2627B8D 4C0EC35A");
 - }
 - private static boolean checkPartner(Context context, String pkgname) {
 - if (sWhitelists == null)
 - buildWhitelists(context);
 - return sWhitelists.test(context, pkgname);
 - }
 - @Override
 - public void onCreate(Bundle savedInstanceState) {
 - super.onCreate(savedInstanceState);
 - setContentView(R.layout.main);
 - // check白名单
 - if (!checkPartner(this, getCallingPackage())) {
 - Toast.makeText(this, "不是白名单内部的。", Toast.LENGTH_LONG).show();
 - finish();
 - return;
 - }
 - }
 - public void onReturnResultClick(View view) {
 - Intent intent = new Intent();
 - intent.putExtra("RESULT", "机密数据");
 - setResult(RESULT_OK, intent);
 - finish();
 - }
 - } [java]
 - PkgCertWhitelists.java
 - [java]
 - package org.jssec.android.shared;
 - import java.util.HashMap;
 - import java.util.Map;
 - import android.content.Context;
 - public class PkgCertWhitelists {
 - private Map
 mWhitelists = new HashMap (); - public boolean add(String pkgname, String sha256) {
 - if (pkgname == null)
 - return false;
 - if (sha256 == null)
 - return false;
 - sha256 = sha256.replaceAll(" ", "");
 - if (sha256.length() != 64)
 - return false;
 - sha256 = sha256.toUpperCase();
 - if (sha256.replaceAll("[0-9A-F]+", "").length() != 0)
 - return false;
 - mWhitelists.put(pkgname, sha256);
 - return true;
 - }
 - public boolean test(Context ctx, String pkgname) {
 - String correctHash = mWhitelists.get(pkgname);
 - return PkgCert.test(ctx, pkgname, correctHash);
 - }
 - }
 - package org.jssec.android.shared;
 - import java.util.HashMap;
 - import java.util.Map;
 - import android.content.Context;
 - public class PkgCertWhitelists {
 - private Map
 mWhitelists = new HashMap (); - public boolean add(String pkgname, String sha256) {
 - if (pkgname == null)
 - return false;
 - if (sha256 == null)
 - return false;
 - sha256 = sha256.replaceAll(" ", "");
 - if (sha256.length() != 64)
 - return false;
 - sha256 = sha256.toUpperCase();
 - if (sha256.replaceAll("[0-9A-F]+", "").length() != 0)
 - return false;
 - mWhitelists.put(pkgname, sha256);
 - return true;
 - }
 - public boolean test(Context ctx, String pkgname) {
 - String correctHash = mWhitelists.get(pkgname);
 - return PkgCert.test(ctx, pkgname, correctHash);
 - }
 - }
 - PkgCert.java
 - [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();
 - }
 - }
 - 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();
 - }
 - }
 
8. 所有根Activity中的intent都能被所有app共享
所有的app,只要按照如下样子,就能取出这台手机上所有task上所有根Activity接受到的intent
- AndroidManifest.xml
 - [html]
 - package="org.jssec.android.intent.maliciousactivity"
 - android:versionCode="1"
 - android:versionName="1.0" >
 - android:minSdkVersion="8"
 - android:targetSdkVersion="15" />
 - android:icon="@drawable/ic_launcher"
 - android:label="@string/app_name"
 - android:theme="@style/AppTheme" >
 - android:name=".MaliciousActivity"
 - android:label="@string/title_activity_main" >
 - package="org.jssec.android.intent.maliciousactivity"
 - android:versionCode="1"
 - android:versionName="1.0" >
 - android:minSdkVersion="8"
 - android:targetSdkVersion="15" />
 - android:icon="@drawable/ic_launcher"
 - android:label="@string/app_name"
 - android:theme="@style/AppTheme" >
 - android:name=".MaliciousActivity"
 - android:label="@string/title_activity_main" >
 - MaliciousActivity.java
 - [java]
 - package org.jssec.android.intent.maliciousactivity;
 - import java.util.List;
 - import android.app.Activity;
 - import android.app.ActivityManager;
 - import android.content.Intent;
 - import android.os.Bundle;
 - import android.util.Log;
 - public class MaliciousActivity extends Activity {
 - @Override
 - public void onCreate(Bundle savedInstanceState) {
 - super.onCreate(savedInstanceState);
 - setContentView(R.layout.malicious_activity);
 - ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
 - List
 list = activityManager - .getRecentTasks(100, ActivityManager.RECENT_WITH_EXCLUDED);
 - for (ActivityManager.RecentTaskInfo r : list) {
 - Intent intent = r.baseIntent;
 - Log.v("baseIntent", intent.toString());
 - }
 - }
 - }
 - package org.jssec.android.intent.maliciousactivity;
 - import java.util.List;
 - import android.app.Activity;
 - import android.app.ActivityManager;
 - import android.content.Intent;
 - import android.os.Bundle;
 - import android.util.Log;
 - public class MaliciousActivity extends Activity {
 - @Override
 - public void onCreate(Bundle savedInstanceState) {
 - super.onCreate(savedInstanceState);
 - setContentView(R.layout.malicious_activity);
 - ActivityManager activityManager = (ActivityManager) getSystemService(ACTIVITY_SERVICE);
 - List
 list = activityManager - .getRecentTasks(100, ActivityManager.RECENT_WITH_EXCLUDED);
 - for (ActivityManager.RecentTaskInfo r : list) {
 - Intent intent = r.baseIntent;
 - Log.v("baseIntent", intent.toString());
 - }
 - }
 - }
 
9. Intent数据遗漏到LogCat的可能性
如果像如下代码,那Intent中发送的数据就会被自动写入LogCat
- [java]
 - Uri uri = Uri.parse("mailto:test@gmail.com");
 - Intent intent = new Intent(Intent.ACTION_SENDTO, uri);
 - startActivity(intent);
 - Uri uri = Uri.parse("mailto:test@gmail.com");
 - Intent intent = new Intent(Intent.ACTION_SENDTO, uri);
 - startActivity(intent);
 - 如果像如下,就能避免
 - [java]
 - Uri uri = Uri.parse("mailto:");
 - Intent intent = new Intent(Intent.ACTION_SENDTO, uri);
 - intent.putExtra(Intent.EXTRA_EMAIL, new String[] {"test@gmail.com"});
 - startActivity(intent);
 - Uri uri = Uri.parse("mailto:");
 - Intent intent = new Intent(Intent.ACTION_SENDTO, uri);
 - intent.putExtra(Intent.EXTRA_EMAIL, new String[] {"test@gmail.com"});
 - startActivity(intent);