How to secure the Private Activities

บทนำ (Overview)

“Private Activities” คือ “Activities” ที่ไม่สามารถเรียกใช้งานจาก “Application” อื่น ๆ ภายในเครื่อง “Android” เดียวกัน ดังนั้นจะเป็นใช้งาน “Activities” ที่มีความปลอดภัยสูงสุด

ระดับของความเสี่ยงและมาตรการป้องกันของการใช้งาน “Activities” ให้ปลอดภัยนั้น ขึ้นอยู่กับการนำไปใช้งาน ซึ่งเราสามารถที่จะจำแนกได้เป็น 4 ประเภทดังต่อไปนี้

เงื่อนไข ประเภท อธิบาย
สำหรับทุก “Application” Public Activity เป็น “Activity” ที่สามารถถูกเรียกใช้งานจาก Application ที่ติดตั้งอยู่ในเครื่องเดียวกัน
เฉพาะ “Application” อนุญาต Partner Activity เป็น “Activity” ที่สามารถเรียกใช้งานเฉพาะ “Application” อนุญาตเท่านั้น
เฉพาะ “Application” ภายใน In-house Activity เป็น “Activity” ที่สามารถใช้งานเฉพาะ Application ที่พัฒนาเฉพาะองค์กรเดียวกันเท่านั้น
ไม่อนุญาต “Application” อื่น Private Activity เป็น “Activity” ที่ไม่สามารถเรียกใช้งานจาก “Application” อื่น ๆ ที่ติดตั้งอยู่ในเครื่องกัน ซึ่งเป็น “Activity” ที่มีความปลอดภัยสูงสุด

ความเสี่ยง (Risks)

ถึงแม้ว่าจะไม่สามารถเรียกใช้งานจาก “Application” อื่น ๆ ได้ แต่ก็ยังมีความเสี่ยงของการอ่าน “Intent” ที่ถูกเรียกใช้งานภายใน “Application” เดียวกัน ดังนั้นจำเป็นที่เราจะต้องตรวจสอบให้แน่ใจว่า ข้อมูลสำคัญ (Sensitive Information) ที่อยู่ใน “Intent” จะต้องไม่ถูกอ่านโดย “Application” ประสงค์ร้าย

การควบคุมความปลอดภัย (Control Activities)

ลำดับ การควบคุม สาเหตุ
ขั้นตอนการสร้าง “Activity”
1 ไม่ระบุใช้งาน “taskAffinity” ตรวจสอบให้แน่ใจว่า “android:taskAffinity” จะต้องไม่มีอยู่ใน “AndroidManifest.xml” ไฟล์ หรือให้ตั้งค่าเป็นค่าตั้งต้น (Default) เพื่อเรียกใช้งาน “Package Name” เป็น “Root tasks” เพื่อป้องกันการอ่านข้อมูลสำคัญ (Sensitive information) ที่อยู่ ใน “Intent” จาก “Application” ประสงค์ร้าย
2 ไม่ระบุใช้งาน “launchMode” ตรวจสอบให้แน่ใจว่า ค่า “launchMode” จะต้องไม่มีอยู่ใน “AndroidManifest.xml” ไฟล์ หรือให้ตั้งค่าเป็นค่าตั้งต้น (Default) ซึ่งก็คือ “Standard” เพื่อป้องกันการอ่านข้อมูลสำคัญ (Sensitive information) ที่อยู่ ใน “Intent” จาก “Application” ประสงค์ร้าย
3 ตั้งค่า “Export” ของ “Activity” สำคัญ เป็น “False” ตรวจสอบให้แน่ใจว่า ค่า “Export” จะต้องไม่มีอยู่ใน “AndroidManifest.xml” ไฟล์ หรือให้ตั้งค่าเป็น “False” เพื่อป้องกันการเรียกใช้งาน Activity จากจาก “Application” ประสงค์ร้าย
4 จัดการข้อมูลนำเข้าอย่างปลอดภัย (Input validation)

ตรวจสอบให้แน่ใจว่า ข้อมูลนำเข้ามีการตรวจสอบ (Input validation) อย่างปลอดภัยดังนี้

  • ข้อมูลนำเข้าจะต้องถูกรูปแบบ (Valid Format) เช่น “String” ไม่รวมอักขระพิเศษเป็นต้น ตามที่ตกลงกันไว้ (Business requirement)
  • ขนาดข้อมูลนำเข้า (Value range)
ขั้นตอนการใช้งาน “Activity”
5 จะต้องไม่ตั้งค่า “FLAG_ACTIVITY_NEW_TASK” สำหรับ Intent ที่เรียกใช้งาน “Activity” ตรวจสอบให้แน่ใจว่า “FLAG_ACTIVITY_NEW_TASK” ไม่ได้ถูกตั้งค่าใน “setFlags()” หรือ “addFlags()” ตอนสร้าง “Intent” ซึ่งก็คือ startActivity() หรือ startActivityForResult() เพื่อป้องกันการเปลี่ยนแปลง “launch mode” ของ “Activity” ที่กำหนดอยู่ใน “AndroidManifest.xml” นำไปสู่อ่านข้อมูลสำคัญ (Sensitive information) ที่อยู่ ใน “Intent” จาก “Application” ประสงค์ร้าย
6 ใช้ “Explicit Intent” โดยระบุ “Classes” ไว้ เพื่อเรียกใช้งาน “Activity” ภายใน “Application” เดียวกัน

ตรวจสอบให้แน่ใจว่า มีการใช้งาน “Explicit Intent” โดยระบุ “Class” ที่จะเรียกใช้ “Activity” เพื่อป้องกันการอ่านข้อมูลสำคัญ (Sensitive information) ที่อยู่ ใน “Intent” จาก “Application” ประสงค์ร้าย

ตัวอย่างเช่น

new Intent(this, PrivateActivity.class);

การสอบทานโปรแกรม (Source code review)

privateActivity01

ขั้นตอนที่ 1 การตั้งค่าใน AndroidManifest.xml

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

    <application android:allowBackup="false" android:icon="@drawable/ic_launcher" android:label="@string/app_name" >
        
        <!-- สำหรับ Private Activity -->
        <!-- Control Activity 1: android:taskAffinity จะต้องไม่มีอยู่ใน AndroidManifest.xml ไฟล์ -->
        <!-- Control Activity 2: android:taskAffinity จะต้องไม่มีอยู่ใน AndroidManifest.xml ไฟล์ หรือถ้ามีจะต้องตั้งเป็น android:launchMode="standard"-->
        <!-- Control Activity 3: ค่า Export จะต้องไม่มีอยู่ใน AndroidManifest.xml ไฟล์ หรือให้ตั้งค่าเป็น False จากตัวอย่างตั้งค่าเป็น False -->
        <activity android:name=".PrivateActivity" android:label="@string/app_name" android:exported="false" />
        
        <!-- ส่วนของ Public Activity -->
        <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>

ขั้นตอนที่ 2 การเรียกใช้ “Private Activity” จาก “Private User Activity”

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) {
    	
	// Control Activity 5: จะต้องไม่มีตั้งค่า FLAG_ACTIVITY_NEW_TASK flag
	// เช่น 
	// Intent i = new Intent(context, ActivityName.class);
	// i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
	//  context.startActivity(i);

	// Control Activity 6: มีการใช้งาน Explicit Intent โดยระบุ Class ที่จะเรียกใช้ Activity
	// จากตัวอย่างข้างล่างมีการกำหนด Class ที่จะเรียก คือ PrivateActivity.class 
	Intent intent = new Intent(this, PrivateActivity.class);
        
	// Sensitive information สามารถส่งได้ผ่าน putExtra เนื่อง Activity ปลายทางอยู่ใน Application เดียวกัน
	intent.putExtra("PARAM", "Sensitive Information");
        
        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");
        	// Control Activity 4: ข้อมูลนำเข้ามีการตรวจสอบ (Input validation) อย่างปลอดภัย
        	// จากตัวอย่างข้างล่าง
        	// - ข้อมูลนำเข้าจะต้องถูกรูปแบบ (Valid Format) = กำหนดเป็น String
        	// - ขนาดข้อมูลนำเข้า (Value range)
        	Toast.makeText(this, String.format("Received result: ", result), Toast.LENGTH_LONG).show();
			break;
		}
	}
}

ขั้นตอนที่ 3 การใช้งาน “Private Activity”

public class PrivateActivity extends Activity {
	
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.private_activity);

	// Control Activity 4: ข้อมูลนำเข้ามีการตรวจสอบ (Input validation) อย่างปลอดภัย
        // จากตัวอย่างข้างล่าง
        // - ข้อมูลนำเข้าจะต้องถูกรูปแบบ (Valid Format) = กำหนดเป็น String
        // - ขนาดข้อมูลนำเข้า (Value range)
        String param = getIntent().getStringExtra("PARAM");
    	Toast.makeText(this, String.format("Received param: ", param), Toast.LENGTH_LONG).show();
	}

	public void onReturnResultClick(View view) {
		
		// Sensitive information สามารถส่งได้ผ่าน putExtra เนื่อง Activity ปลายทางอยู่ใน Application เดียวกัน
		Intent intent = new Intent();
		intent.putExtra("RESULT", "Sensitive Information");
		setResult(RESULT_OK, intent);
		finish();
	}
}

เอกสารอ้างอิง (Referrences)

  • Android Application Secure Design/Secure CodingGuidebook, February 1st, 2016 Edition, Japan Smartphone Security Association (JSSEC)
  • https://developer.android.com/guide/topics/manifest/activity-element.html

 

ใส่ความเห็น