4.1.1.1 创建/使用私有活动

私有活动是其他应用程序无法启动的活动,因此它是最安全的活动。

当使用仅在应用程序中使用的活动(私有活动)时,只要你对类使用显示意图,那么你不必担心将它意外发送到任何其他应用程序。 但是,第三方应用程序可能会读取用于启动活动的意图。 因此,如果你将敏感信息放入用于启动活动的意图中,有必要采取对策,来确保它不会被恶意第三方读取。

下面展示了如何创建私有活动的示例代码。

要点(创建活动):

  1. 不要指定taskAffinity

  2. 不要指定launchMode

  3. 将导出属性明确设置为false

  4. 仔细和安全地处理收到的意图,即使意图从相同的应用发送。

  5. 敏感信息可以发送,因为它发送和接收所有同一应用中的信息。

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="org.jssec.android.activity.privateactivity" >
    
    <application
        android:allowBackup="false"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name" >
        
        <!-- Private activity -->
        <!-- *** POINT 1 *** Do not specify taskAffinity -->
        <!-- *** POINT 2 *** Do not specify launchMode -->
        <!-- *** POINT 3 *** Explicitly set the exported attribute to false. -->
        <activity
            android:name=".PrivateActivity"
            android:label="@string/app_name"
            android:exported="false" />
        
        <!-- Public activity launched by launcher -->
        <activity
            android:name=".PrivateUserActivity"
            android:label="@string/app_name"
            android:exported="true" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

PrivateActivity.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);
        // *** POINT 4 *** Handle the received Intent carefully and securely, even though the Intent was sent from the same 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 5 *** Sensitive information can be sent since it is sending and receiving all within the same application.
        Intent intent = new Intent();
        intent.putExtra("RESULT", "Sensitive Info");
        setResult(RESULT_OK, intent);
        finish();
    }
}

下面展示如何使用私有活动的示例代码。

要点(使用活动);

  1. 不要为意图设置FLAG_ACTIVITY_NEW_TASK标志来启动活动。

  2. 使用显式意图,以及用于调用相同应用中的活动的特定的类。

  3. 由于目标活动位于同一个应用中,因此只能通过putExtra()发送敏感信息 [1]。

警告:如果不遵守第 1, 2 和 6 点,第三方可能会读到意图。 更多详细信息,请参阅第 4.1.2.2 和 4.1.2.3 节。

  1. 即使数据来自同一应用中的活动,也要小心并安全地处理收到的结果数据。

PrivateUserActivity.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) {
        // *** POINT 6 *** Do not set the FLAG_ACTIVITY_NEW_TASK flag for intents to start an activity.
        // *** POINT 7 *** Use the explicit Intents with the class specified to call an activity in the same application.
        Intent intent = new Intent(this, PrivateActivity.class);
        // *** POINT 8 *** Sensitive information can be sent only by putExtra() since the destination activity is in the same application.
        intent.putExtra("PARAM", "Sensitive Info");
        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");
                // *** POINT 9 *** Handle the received data carefully and securely,
                // even though the data comes from an activity within the same application.
                // Omitted, since this is a sample. Please refer to "3.2 Handling Input Data Carefully and Securely."
                Toast.makeText(this, String.format("Received result: ¥"%s¥"", result), Toast.LENGTH_LONG).show();
                break;
        }
    }
}

书籍推荐