আপনার অ্যাপের নিরাপত্তা উন্নত করুন, আপনার অ্যাপের নিরাপত্তা উন্নত করুন, আপনার অ্যাপের নিরাপত্তা উন্নত করুন

আপনার অ্যাপকে আরও সুরক্ষিত করে আপনি ব্যবহারকারীর বিশ্বাস এবং ডিভাইসের অখণ্ডতা রক্ষা করতে সাহায্য করেন।

এই পৃষ্ঠাটি বেশ কয়েকটি সর্বোত্তম অনুশীলন উপস্থাপন করে যা আপনার অ্যাপের নিরাপত্তার উপর একটি উল্লেখযোগ্য, ইতিবাচক প্রভাব ফেলে।

নিরাপদ যোগাযোগ প্রয়োগ করুন

যখন আপনি আপনার অ্যাপ এবং অন্যান্য অ্যাপের মধ্যে বা আপনার অ্যাপ এবং কোনও ওয়েবসাইটের মধ্যে বিনিময় করা ডেটাকে সুরক্ষিত করেন, তখন আপনি আপনার অ্যাপের স্থায়িত্বকে উন্নত করেন এবং আপনার পাঠানো ও গ্রহণ করা ডেটাকে সুরক্ষিত করেন।

অ্যাপের মধ্যে যোগাযোগ রক্ষা করুন

আরও নিরাপদে অ্যাপগুলির মধ্যে যোগাযোগ করতে, একটি অ্যাপ চয়নকারী, স্বাক্ষর-ভিত্তিক অনুমতি এবং অ-রপ্তানিকৃত সামগ্রী প্রদানকারীদের সাথে অন্তর্নিহিত উদ্দেশ্যগুলি ব্যবহার করুন৷

একটি অ্যাপ চয়নকারী দেখান৷

যদি একটি অন্তর্নিহিত উদ্দেশ্য ব্যবহারকারীর ডিভাইসে কমপক্ষে দুটি সম্ভাব্য অ্যাপ চালু করতে পারে, তাহলে স্পষ্টভাবে একটি অ্যাপ চয়নকারী দেখান। এই মিথস্ক্রিয়া কৌশলটি ব্যবহারকারীদের তাদের বিশ্বাসযোগ্য একটি অ্যাপে সংবেদনশীল তথ্য স্থানান্তর করতে দেয়।

কোটলিন

val intent = Intent(Intent.ACTION_SEND)
val possibleActivitiesList: List<ResolveInfo> =
        packageManager.queryIntentActivities(intent, PackageManager.MATCH_ALL)

// Verify that an activity in at least two apps on the user's device
// can handle the intent. Otherwise, start the intent only if an app
// on the user's device can handle the intent.
if (possibleActivitiesList.size > 1) {

    // Create intent to show chooser.
    // Title is something similar to "Share this photo with."

    val chooser = resources.getString(R.string.chooser_title).let { title ->
        Intent.createChooser(intent, title)
    }
    startActivity(chooser)
} else if (intent.resolveActivity(packageManager) != null) {
    startActivity(intent)
}

জাভা

Intent intent = new Intent(Intent.ACTION_SEND);
List<ResolveInfo> possibleActivitiesList = getPackageManager()
        .queryIntentActivities(intent, PackageManager.MATCH_ALL);

// Verify that an activity in at least two apps on the user's device
// can handle the intent. Otherwise, start the intent only if an app
// on the user's device can handle the intent.
if (possibleActivitiesList.size() > 1) {

    // Create intent to show chooser.
    // Title is something similar to "Share this photo with."

    String title = getResources().getString(R.string.chooser_title);
    Intent chooser = Intent.createChooser(intent, title);
    startActivity(chooser);
} else if (intent.resolveActivity(getPackageManager()) != null) {
    startActivity(intent);
}

সম্পর্কিত তথ্য:

স্বাক্ষর-ভিত্তিক অনুমতি প্রয়োগ করুন

আপনার নিয়ন্ত্রণ বা মালিকানাধীন দুটি অ্যাপের মধ্যে ডেটা ভাগ করার সময়, স্বাক্ষর-ভিত্তিক অনুমতিগুলি ব্যবহার করুন৷ এই অনুমতিগুলির জন্য ব্যবহারকারীর নিশ্চিতকরণের প্রয়োজন হয় না এবং পরিবর্তে পরীক্ষা করে দেখুন যে ডেটা অ্যাক্সেস করা অ্যাপগুলি একই সাইনিং কী ব্যবহার করে সাইন করা হয়েছে। অতএব, এই অনুমতিগুলি আরও সুগমিত, নিরাপদ ব্যবহারকারীর অভিজ্ঞতা প্রদান করে।

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapp">
    <permission android:name="my_custom_permission_name"
                android:protectionLevel="signature" />

সম্পর্কিত তথ্য:

আপনার অ্যাপের বিষয়বস্তু প্রদানকারীদের অ্যাক্সেসের অনুমতি দিন

যদি না আপনি আপনার অ্যাপ থেকে ডেটা পাঠাতে চান এমন একটি ভিন্ন অ্যাপে যা আপনার নিজের নয়, স্পষ্টভাবে অন্য ডেভেলপারদের অ্যাপগুলিকে আপনার অ্যাপের ContentProvider অবজেক্ট অ্যাক্সেস করা থেকে বিরত রাখুন। এই সেটিংটি বিশেষভাবে গুরুত্বপূর্ণ যদি আপনার অ্যাপটি Android 4.1.1 (API লেভেল 16) বা তার কম সংস্করণে চলমান ডিভাইসগুলিতে ইনস্টল করা যায়, কারণ <provider> উপাদানটির android:exported বৈশিষ্ট্যটি Android-এর সেই সংস্করণগুলিতে ডিফল্টরূপে true

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapp">
    <application ... >
        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="com.example.myapp.fileprovider"
            ...
            android:exported="false">
            <!-- Place child elements of <provider> here. -->
        </provider>
        ...
    </application>
</manifest>

সংবেদনশীল তথ্য দেখানোর আগে শংসাপত্রের জন্য জিজ্ঞাসা করুন

ব্যবহারকারীদের কাছ থেকে শংসাপত্রের অনুরোধ করার সময় যাতে তারা আপনার অ্যাপে সংবেদনশীল তথ্য বা প্রিমিয়াম সামগ্রী অ্যাক্সেস করতে পারে, একটি পিন/পাসওয়ার্ড/প্যাটার্ন বা বায়োমেট্রিক শংসাপত্রের জন্য জিজ্ঞাসা করুন, যেমন মুখ শনাক্তকরণ বা আঙুলের ছাপ শনাক্তকরণ৷

কীভাবে বায়োমেট্রিক শংসাপত্রের অনুরোধ করতে হয় সে সম্পর্কে আরও জানতে, বায়োমেট্রিক প্রমাণীকরণ সম্পর্কে নির্দেশিকাটি দেখুন।

নেটওয়ার্ক নিরাপত্তা ব্যবস্থা প্রয়োগ করুন

নিম্নলিখিত বিভাগগুলি বর্ণনা করে যে আপনি কীভাবে আপনার অ্যাপের নেটওয়ার্ক নিরাপত্তা উন্নত করতে পারেন৷

TLS ট্রাফিক ব্যবহার করুন

যদি আপনার অ্যাপটি এমন একটি ওয়েব সার্ভারের সাথে যোগাযোগ করে যার একটি সুপরিচিত, বিশ্বস্ত সার্টিফিকেট অথরিটি (CA) দ্বারা জারি করা শংসাপত্র রয়েছে, তাহলে নিম্নোক্ত মত একটি HTTPS অনুরোধ ব্যবহার করুন:

কোটলিন

val url = URL("https://www.google.com")
val urlConnection = url.openConnection() as HttpsURLConnection
urlConnection.connect()
urlConnection.inputStream.use {
    ...
}

জাভা

URL url = new URL("https://www.google.com");
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
urlConnection.connect();
InputStream in = urlConnection.getInputStream();

একটি নেটওয়ার্ক নিরাপত্তা কনফিগারেশন যোগ করুন

যদি আপনার অ্যাপ নতুন বা কাস্টম CA ব্যবহার করে, তাহলে আপনি একটি কনফিগারেশন ফাইলে আপনার নেটওয়ার্কের নিরাপত্তা সেটিংস ঘোষণা করতে পারেন। এই প্রক্রিয়াটি আপনাকে কোনো অ্যাপ কোড পরিবর্তন না করেই কনফিগারেশন তৈরি করতে দেয়।

আপনার অ্যাপে একটি নেটওয়ার্ক নিরাপত্তা কনফিগারেশন ফাইল যোগ করতে, এই পদক্ষেপগুলি অনুসরণ করুন:

  1. আপনার অ্যাপের ম্যানিফেস্টে কনফিগারেশন ঘোষণা করুন:
  2. <manifest ... >
        <application
            android:networkSecurityConfig="@xml/network_security_config"
            ... >
            <!-- Place child elements of <application> element here. -->
        </application>
    </manifest>
  3. res/xml/network_security_config.xml এ অবস্থিত একটি XML রিসোর্স ফাইল যোগ করুন।

    নির্দিষ্ট করুন যে নির্দিষ্ট ডোমেনে সমস্ত ট্র্যাফিক অবশ্যই ক্লিয়ার-টেক্সট অক্ষম করে HTTPS ব্যবহার করবে:

    <network-security-config>
        <domain-config cleartextTrafficPermitted="false">
            <domain includeSubdomains="true">secure.example.com</domain>
            ...
        </domain-config>
    </network-security-config>

    বিকাশ প্রক্রিয়া চলাকালীন, আপনি ব্যবহারকারী-ইনস্টল করা শংসাপত্রগুলিকে স্পষ্টভাবে অনুমতি দিতে <debug-overrides> উপাদান ব্যবহার করতে পারেন। এই উপাদানটি অ্যাপের রিলিজ কনফিগারেশনকে প্রভাবিত না করেই ডিবাগিং এবং পরীক্ষার সময় আপনার অ্যাপের নিরাপত্তা-সমালোচনামূলক বিকল্পগুলিকে ওভাররাইড করে। নিম্নলিখিত স্নিপেটটি আপনার অ্যাপের নেটওয়ার্ক নিরাপত্তা কনফিগারেশন XML ফাইলে এই উপাদানটিকে কীভাবে সংজ্ঞায়িত করতে হয় তা দেখায়:

    <network-security-config>
        <debug-overrides>
            <trust-anchors>
                <certificates src="user" />
            </trust-anchors>
        </debug-overrides>
    </network-security-config>

সম্পর্কিত তথ্য: নেটওয়ার্ক নিরাপত্তা কনফিগারেশন

আপনার নিজের ট্রাস্ট ম্যানেজার তৈরি করুন

আপনার TLS পরীক্ষকের প্রতিটি শংসাপত্র গ্রহণ করা উচিত নয়। নিম্নলিখিত শর্তগুলির মধ্যে একটি আপনার ব্যবহারের ক্ষেত্রে প্রযোজ্য হলে আপনাকে একটি ট্রাস্ট ম্যানেজার সেট আপ করতে এবং সমস্ত TLS সতর্কতাগুলি পরিচালনা করতে হতে পারে:

  • আপনি একটি ওয়েব সার্ভারের সাথে যোগাযোগ করছেন যাতে একটি নতুন বা কাস্টম CA দ্বারা স্বাক্ষরিত একটি শংসাপত্র রয়েছে৷
  • আপনি যে ডিভাইসটি ব্যবহার করছেন তার দ্বারা সেই CA বিশ্বাসযোগ্য নয়৷
  • আপনি একটি নেটওয়ার্ক নিরাপত্তা কনফিগারেশন ব্যবহার করতে পারবেন না৷

এই পদক্ষেপগুলি কীভাবে সম্পূর্ণ করবেন সে সম্পর্কে আরও জানতে, একটি অজানা শংসাপত্র কর্তৃপক্ষ পরিচালনার বিষয়ে আলোচনাটি দেখুন।

সম্পর্কিত তথ্য:

WebView অবজেক্ট সাবধানে ব্যবহার করুন

আপনার অ্যাপের WebView অবজেক্টগুলি ব্যবহারকারীদের এমন সাইটগুলিতে নেভিগেট করতে দেয় না যা আপনার নিয়ন্ত্রণের বাইরে। যখনই সম্ভব, আপনার অ্যাপের WebView অবজেক্ট দ্বারা লোড করা সামগ্রীকে সীমাবদ্ধ করতে অনুমতি তালিকা ব্যবহার করুন।

উপরন্তু, জাভাস্ক্রিপ্ট ইন্টারফেস সমর্থন সক্ষম করবেন না যদি না আপনি সম্পূর্ণরূপে আপনার অ্যাপের WebView অবজেক্টের বিষয়বস্তু নিয়ন্ত্রণ এবং বিশ্বাস করেন।

HTML বার্তা চ্যানেল ব্যবহার করুন

যদি আপনার অ্যাপ অবশ্যই Android 6.0 (API লেভেল 23) এবং তার উপরে চলমান ডিভাইসগুলিতে JavaScript ইন্টারফেস সমর্থন ব্যবহার করে, তাহলে নিম্নলিখিত কোড স্নিপেটে দেখানো হিসাবে ওয়েবসাইট এবং আপনার অ্যাপের মধ্যে যোগাযোগের পরিবর্তে HTML বার্তা চ্যানেলগুলি ব্যবহার করুন:

কোটলিন

val myWebView: WebView = findViewById(R.id.webview)

// channel[0] and channel[1] represent the two ports.
// They are already entangled with each other and have been started.
val channel: Array<out WebMessagePort> = myWebView.createWebMessageChannel()

// Create handler for channel[0] to receive messages.
channel[0].setWebMessageCallback(object : WebMessagePort.WebMessageCallback() {

    override fun onMessage(port: WebMessagePort, message: WebMessage) {
        Log.d(TAG, "On port $port, received this message: $message")
    }
})

// Send a message from channel[1] to channel[0].
channel[1].postMessage(WebMessage("My secure message"))

জাভা

WebView myWebView = (WebView) findViewById(R.id.webview);

// channel[0] and channel[1] represent the two ports.
// They are already entangled with each other and have been started.
WebMessagePort[] channel = myWebView.createWebMessageChannel();

// Create handler for channel[0] to receive messages.
channel[0].setWebMessageCallback(new WebMessagePort.WebMessageCallback() {
    @Override
    public void onMessage(WebMessagePort port, WebMessage message) {
         Log.d(TAG, "On port " + port + ", received this message: " + message);
    }
});

// Send a message from channel[1] to channel[0].
channel[1].postMessage(new WebMessage("My secure message"));

সম্পর্কিত তথ্য:

সঠিক অনুমতি প্রদান করুন

আপনার অ্যাপটি সঠিকভাবে কাজ করার জন্য প্রয়োজনীয় ন্যূনতম সংখ্যক অনুমতির অনুরোধ করুন। যখন সম্ভব, আপনার অ্যাপের আর প্রয়োজন না হলে অনুমতি ত্যাগ করুন।

অনুমতি স্থগিত করতে উদ্দেশ্য ব্যবহার করুন

যখনই সম্ভব, অন্য অ্যাপে সম্পন্ন করা যেতে পারে এমন একটি অ্যাকশন সম্পূর্ণ করার জন্য আপনার অ্যাপে অনুমতি যোগ করবেন না। পরিবর্তে, ইতিমধ্যেই প্রয়োজনীয় অনুমতি রয়েছে এমন একটি ভিন্ন অ্যাপে অনুরোধটি পিছিয়ে দেওয়ার জন্য একটি উদ্দেশ্য ব্যবহার করুন।

নিম্নলিখিত উদাহরণটি দেখায় যে কীভাবে ব্যবহারকারীদের READ_CONTACTS এবং WRITE_CONTACTS অনুমতির অনুরোধ করার পরিবর্তে একটি পরিচিতি অ্যাপে নির্দেশিত করতে একটি অভিপ্রায় ব্যবহার করতে হয়:

কোটলিন

// Delegates the responsibility of creating the contact to a contacts app,
// which has already been granted the appropriate WRITE_CONTACTS permission.
Intent(Intent.ACTION_INSERT).apply {
    type = ContactsContract.Contacts.CONTENT_TYPE
}.also { intent ->
    // Make sure that the user has a contacts app installed on their device.
    intent.resolveActivity(packageManager)?.run {
        startActivity(intent)
    }
}

জাভা

// Delegates the responsibility of creating the contact to a contacts app,
// which has already been granted the appropriate WRITE_CONTACTS permission.
Intent insertContactIntent = new Intent(Intent.ACTION_INSERT);
insertContactIntent.setType(ContactsContract.Contacts.CONTENT_TYPE);

// Make sure that the user has a contacts app installed on their device.
if (insertContactIntent.resolveActivity(getPackageManager()) != null) {
    startActivity(insertContactIntent);
}

উপরন্তু, যদি আপনার অ্যাপটিকে ফাইল-ভিত্তিক I/O- যেমন সঞ্চয়স্থান অ্যাক্সেস করা বা একটি ফাইল বেছে নেওয়ার প্রয়োজন হয়- তবে এটির বিশেষ অনুমতির প্রয়োজন নেই কারণ সিস্টেমটি আপনার অ্যাপের হয়ে কাজগুলি সম্পূর্ণ করতে পারে। আরও ভাল, কোনও ব্যবহারকারী একটি নির্দিষ্ট ইউআরআই-তে সামগ্রী নির্বাচন করার পরে, কলিং অ্যাপটি নির্বাচিত সংস্থানের অনুমতি পায়।

সম্পর্কিত তথ্য:

অ্যাপ জুড়ে নিরাপদে ডেটা শেয়ার করুন

আরও নিরাপদ পদ্ধতিতে অন্যান্য অ্যাপের সাথে আপনার অ্যাপের বিষয়বস্তু শেয়ার করতে এই সবথেকে ভাল অভ্যাসগুলি অনুসরণ করুন:

  • প্রয়োজন অনুযায়ী শুধুমাত্র-পঠন বা শুধুমাত্র লেখার অনুমতি প্রয়োগ করুন।
  • FLAG_GRANT_READ_URI_PERMISSION এবং FLAG_GRANT_WRITE_URI_PERMISSION ফ্ল্যাগগুলি ব্যবহার করে ক্লায়েন্টদের ডেটাতে এককালীন অ্যাক্সেস প্রদান করুন৷
  • ডেটা শেয়ার করার সময়, content:// URIs ব্যবহার করুন, file:// URIs নয়। FileProvider এর উদাহরণগুলি আপনার জন্য এটি করে।

নিচের কোড স্নিপেটটি দেখায় কিভাবে ইউআরআই অনুমতি মঞ্জুর ফ্ল্যাগ ব্যবহার করতে হয় এবং একটি পৃথক পিডিএফ ভিউয়ার অ্যাপে একটি অ্যাপের পিডিএফ ফাইল প্রদর্শন করতে সামগ্রী প্রদানকারীর অনুমতি দেয়:

কোটলিন

// Create an Intent to launch a PDF viewer for a file owned by this app.
Intent(Intent.ACTION_VIEW).apply {
    data = Uri.parse("content://com.example/personal-info.pdf")

    // This flag gives the started app read access to the file.
    addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}.also { intent ->
    // Make sure that the user has a PDF viewer app installed on their device.
    intent.resolveActivity(packageManager)?.run {
        startActivity(intent)
    }
}

জাভা

// Create an Intent to launch a PDF viewer for a file owned by this app.
Intent viewPdfIntent = new Intent(Intent.ACTION_VIEW);
viewPdfIntent.setData(Uri.parse("content://com.example/personal-info.pdf"));

// This flag gives the started app read access to the file.
viewPdfIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

// Make sure that the user has a PDF viewer app installed on their device.
if (viewPdfIntent.resolveActivity(getPackageManager()) != null) {
    startActivity(viewPdfIntent);
}

দ্রষ্টব্য: লিখনযোগ্য অ্যাপ হোম ডিরেক্টরি থেকে ফাইলগুলি সম্পাদন করা একটি W^X লঙ্ঘন । এই কারণে, অবিশ্বস্ত অ্যাপগুলি যেগুলি Android 10 (API স্তর 29) এবং উচ্চতরকে লক্ষ্য করে তারা অ্যাপের হোম ডিরেক্টরির মধ্যে ফাইলগুলিতে exec() চালু করতে পারে না, শুধুমাত্র একটি অ্যাপের APK ফাইলের মধ্যে এমবেড করা বাইনারি কোড। এছাড়াও, যে অ্যাপগুলি Android 10 এবং উচ্চতরকে লক্ষ্য করে, সেগুলি মেমরিতে, dlopen() দিয়ে খোলা ফাইলগুলি থেকে এক্সিকিউটেবল কোড পরিবর্তন করতে পারে না৷ এতে টেক্সট রিলোকেশন সহ যেকোনও শেয়ার করা অবজেক্ট ( .so ) ফাইল অন্তর্ভুক্ত থাকে।

সম্পর্কিত তথ্য: android:grantUriPermissions

নিরাপদে ডেটা সংরক্ষণ করুন

যদিও আপনার অ্যাপের সংবেদনশীল ব্যবহারকারীর তথ্যে অ্যাক্সেসের প্রয়োজন হতে পারে, ব্যবহারকারীরা আপনার অ্যাপকে শুধুমাত্র তাদের ডেটাতে অ্যাক্সেস দেয় যদি তারা বিশ্বাস করে যে আপনি এটি সঠিকভাবে সুরক্ষিত রেখেছেন।

অভ্যন্তরীণ স্টোরেজের মধ্যে ব্যক্তিগত তথ্য সংরক্ষণ করুন

ডিভাইসের অভ্যন্তরীণ স্টোরেজের মধ্যে সমস্ত ব্যক্তিগত ব্যবহারকারীর ডেটা সঞ্চয় করুন, যা প্রতি অ্যাপে স্যান্ডবক্স করা হয়। আপনার অ্যাপকে এই ফাইলগুলি দেখার অনুমতির অনুরোধ করার প্রয়োজন নেই এবং অন্যান্য অ্যাপগুলি ফাইলগুলি অ্যাক্সেস করতে পারে না৷ একটি অতিরিক্ত নিরাপত্তা ব্যবস্থা হিসাবে, ব্যবহারকারী যখন একটি অ্যাপ আনইনস্টল করেন, তখন ডিভাইসটি অভ্যন্তরীণ স্টোরেজের মধ্যে অ্যাপটি সংরক্ষিত সমস্ত ফাইল মুছে দেয়।

নিম্নলিখিত কোড স্নিপেট অভ্যন্তরীণ সঞ্চয়স্থানে ডেটা লেখার একটি উপায় প্রদর্শন করে:

কোটলিন

// Creates a file with this name, or replaces an existing file
// that has the same name. Note that the file name cannot contain
// path separators.
val FILE_NAME = "sensitive_info.txt"
val fileContents = "This is some top-secret information!"
File(filesDir, FILE_NAME).bufferedWriter().use { writer ->
    writer.write(fileContents)
}

জাভা

// Creates a file with this name, or replaces an existing file
// that has the same name. Note that the file name cannot contain
// path separators.
final String FILE_NAME = "sensitive_info.txt";
String fileContents = "This is some top-secret information!";
try (BufferedWriter writer =
             new BufferedWriter(new FileWriter(new File(getFilesDir(), FILE_NAME)))) {
    writer.write(fileContents);
} catch (IOException e) {
    // Handle exception.
}

নিম্নলিখিত কোড স্নিপেট অভ্যন্তরীণ সঞ্চয়স্থান থেকে ডেটা পড়া, বিপরীত অপারেশন দেখায়:

কোটলিন

val FILE_NAME = "sensitive_info.txt"
val contents = File(filesDir, FILE_NAME).bufferedReader().useLines { lines ->
    lines.fold("") { working, line ->
        "$working\n$line"
    }
}

জাভা

final String FILE_NAME = "sensitive_info.txt";
StringBuffer stringBuffer = new StringBuffer();
try (BufferedReader reader =
             new BufferedReader(new FileReader(new File(getFilesDir(), FILE_NAME)))) {

    String line = reader.readLine();
    while (line != null) {
        stringBuffer.append(line).append('\n');
        line = reader.readLine();
    }
} catch (IOException e) {
    // Handle exception.
}

সম্পর্কিত তথ্য:

ব্যবহারের ক্ষেত্রের উপর ভিত্তি করে বাহ্যিক সঞ্চয়স্থানে ডেটা সংরক্ষণ করুন

বড়, অ-সংবেদনশীল ফাইলগুলির জন্য বাহ্যিক সঞ্চয়স্থান ব্যবহার করুন যা আপনার অ্যাপের জন্য নির্দিষ্ট এবং সেইসাথে আপনার অ্যাপ অন্যান্য অ্যাপের সাথে শেয়ার করা ফাইলগুলির জন্য। আপনি যে নির্দিষ্ট APIগুলি ব্যবহার করেন তা নির্ভর করে আপনার অ্যাপটি অ্যাপ-নির্দিষ্ট ফাইলগুলি অ্যাক্সেস করতে বা শেয়ার করা ফাইলগুলি অ্যাক্সেস করার জন্য ডিজাইন করা হয়েছে কিনা তার উপর।

যদি কোনো ফাইলে ব্যক্তিগত বা সংবেদনশীল তথ্য না থাকে কিন্তু শুধুমাত্র আপনার অ্যাপে ব্যবহারকারীকে মূল্য প্রদান করে, তাহলে ফাইলটিকে এক্সটার্নাল স্টোরেজে একটি অ্যাপ-নির্দিষ্ট ডিরেক্টরিতে সংরক্ষণ করুন।

যদি আপনার অ্যাপের এমন কোনো ফাইল অ্যাক্সেস বা স্টোর করার প্রয়োজন হয় যা অন্য অ্যাপের মান প্রদান করে, তাহলে আপনার ব্যবহারের ক্ষেত্রে নির্ভর করে নিম্নলিখিত APIগুলির মধ্যে একটি ব্যবহার করুন:

স্টোরেজ ভলিউমের প্রাপ্যতা পরীক্ষা করুন

যদি আপনার অ্যাপটি একটি অপসারণযোগ্য বাহ্যিক স্টোরেজ ডিভাইসের সাথে ইন্টারঅ্যাক্ট করে, তাহলে মনে রাখবেন যে ব্যবহারকারী স্টোরেজ ডিভাইসটি সরিয়ে ফেলতে পারে যখন আপনার অ্যাপটি অ্যাক্সেস করার চেষ্টা করছে। স্টোরেজ ডিভাইস উপলব্ধ কিনা তা যাচাই করতে যুক্তি অন্তর্ভুক্ত করুন।

ডেটার বৈধতা পরীক্ষা করুন

যদি আপনার অ্যাপটি বাহ্যিক স্টোরেজ থেকে ডেটা ব্যবহার করে, তবে নিশ্চিত করুন যে ডেটার বিষয়বস্তুগুলি দূষিত বা সংশোধন করা হয়নি। স্থিতিশীল বিন্যাসে আর নেই এমন ফাইলগুলি পরিচালনা করার জন্য যুক্তি অন্তর্ভুক্ত করুন।

নিম্নলিখিত কোড স্নিপেটে একটি হ্যাশ যাচাইকারীর উদাহরণ রয়েছে:

কোটলিন

val hash = calculateHash(stream)
// Store "expectedHash" in a secure location.
if (hash == expectedHash) {
    // Work with the content.
}

// Calculating the hash code can take quite a bit of time, so it shouldn't
// be done on the main thread.
suspend fun calculateHash(stream: InputStream): String {
    return withContext(Dispatchers.IO) {
        val digest = MessageDigest.getInstance("SHA-512")
        val digestStream = DigestInputStream(stream, digest)
        while (digestStream.read() != -1) {
            // The DigestInputStream does the work; nothing for us to do.
        }
        digest.digest().joinToString(":") { "%02x".format(it) }
    }
}

জাভা

Executor threadPoolExecutor = Executors.newFixedThreadPool(4);
private interface HashCallback {
    void onHashCalculated(@Nullable String hash);
}

boolean hashRunning = calculateHash(inputStream, threadPoolExecutor, hash -> {
    if (Objects.equals(hash, expectedHash)) {
        // Work with the content.
    }
});

if (!hashRunning) {
    // There was an error setting up the hash function.
}

private boolean calculateHash(@NonNull InputStream stream,
                              @NonNull Executor executor,
                              @NonNull HashCallback hashCallback) {
    final MessageDigest digest;
    try {
        digest = MessageDigest.getInstance("SHA-512");
    } catch (NoSuchAlgorithmException nsa) {
        return false;
    }

    // Calculating the hash code can take quite a bit of time, so it shouldn't
    // be done on the main thread.
    executor.execute(() -> {
        String hash;
        try (DigestInputStream digestStream =
                new DigestInputStream(stream, digest)) {
            while (digestStream.read() != -1) {
                // The DigestInputStream does the work; nothing for us to do.
            }
            StringBuilder builder = new StringBuilder();
            for (byte aByte : digest.digest()) {
                builder.append(String.format("%02x", aByte)).append(':');
            }
            hash = builder.substring(0, builder.length() - 1);
        } catch (IOException e) {
            hash = null;
        }

        final String calculatedHash = hash;
        runOnUiThread(() -> hashCallback.onHashCalculated(calculatedHash));
    });
    return true;
}

ক্যাশে ফাইলগুলিতে শুধুমাত্র অ-সংবেদনশীল ডেটা সংরক্ষণ করুন

অ-সংবেদনশীল অ্যাপ ডেটাতে দ্রুত অ্যাক্সেস প্রদান করতে, এটি ডিভাইসের ক্যাশে সংরক্ষণ করুন। 1 MB এর চেয়ে বড় ক্যাশেগুলির জন্য, getExternalCacheDir() ব্যবহার করুন। 1 MB বা ছোট ক্যাশেগুলির জন্য, getCacheDir() ব্যবহার করুন৷ উভয় পদ্ধতিই আপনাকে File অবজেক্ট প্রদান করে যাতে আপনার অ্যাপের ক্যাশে করা ডেটা থাকে।

নিম্নলিখিত কোড স্নিপেট দেখায় যে আপনার অ্যাপ সম্প্রতি ডাউনলোড করা একটি ফাইল কীভাবে ক্যাশে করবেন:

কোটলিন

val cacheFile = File(myDownloadedFileUri).let { fileToCache ->
    File(cacheDir.path, fileToCache.name)
}

জাভা

File cacheDir = getCacheDir();
File fileToCache = new File(myDownloadedFileUri);
String fileToCacheName = fileToCache.getName();
File cacheFile = new File(cacheDir.getPath(), fileToCacheName);

দ্রষ্টব্য: আপনি শেয়ার্ড স্টোরেজের মধ্যে আপনার অ্যাপের ক্যাশে রাখার জন্য getExternalCacheDir() ব্যবহার করলে, আপনার অ্যাপ চলাকালীন ব্যবহারকারী এই স্টোরেজ ধারণকারী মিডিয়া বের করে দিতে পারে। এই ব্যবহারকারীর আচরণের কারণে ক্যাশে মিসকে সুন্দরভাবে পরিচালনা করার জন্য যুক্তি অন্তর্ভুক্ত করুন।

সতর্কতা: এই ফাইলগুলিতে কোন নিরাপত্তা বলবৎ নেই। তাই, যেকোন অ্যাপ যেটি Android 10 (API লেভেল 29) বা তার নিচের দিকে লক্ষ্য করে এবং WRITE_EXTERNAL_STORAGE অনুমতি আছে তারা এই ক্যাশের বিষয়বস্তু অ্যাক্সেস করতে পারে।

সম্পর্কিত তথ্য: ডেটা এবং ফাইল স্টোরেজ ওভারভিউ

ব্যক্তিগত মোডে SharedPreferences ব্যবহার করুন

আপনার অ্যাপের SharedPreferences অবজেক্ট তৈরি বা অ্যাক্সেস করতে getSharedPreferences() ব্যবহার করার সময়, MODE_PRIVATE ব্যবহার করুন। এইভাবে, শুধুমাত্র আপনার অ্যাপ শেয়ার করা পছন্দ ফাইলের মধ্যে তথ্য অ্যাক্সেস করতে পারে।

আপনি যদি সমস্ত অ্যাপ জুড়ে ডেটা ভাগ করতে চান, তাহলে SharedPreferences অবজেক্ট ব্যবহার করবেন না। পরিবর্তে, অ্যাপ্লিকেশানগুলিতে নিরাপদে ডেটা ভাগ করতে পদক্ষেপগুলি অনুসরণ করুন৷

সিকিউরিটি লাইব্রেরি এনক্রিপ্টেড শেয়ারডপ্রেফারেন্স ক্লাসও প্রদান করে যা শেয়ারডপ্রেফারেন্স ক্লাসকে মোড়ানো হয় এবং কী এবং মানগুলি স্বয়ংক্রিয়ভাবে এনক্রিপ্ট করে।

সম্পর্কিত তথ্য:

পরিষেবা এবং নির্ভরতা আপ টু ডেট রাখুন

বেশিরভাগ অ্যাপ বিশেষায়িত কাজগুলি সম্পূর্ণ করতে বাহ্যিক লাইব্রেরি এবং ডিভাইস সিস্টেম তথ্য ব্যবহার করে। আপনার অ্যাপের নির্ভরতা আপ টু ডেট রেখে, আপনি যোগাযোগের এই পয়েন্টগুলিকে আরও সুরক্ষিত করে তোলেন৷

Google Play পরিষেবা নিরাপত্তা প্রদানকারী চেক করুন

দ্রষ্টব্য: এই বিভাগটি শুধুমাত্র এমন অ্যাপগুলির জন্য প্রযোজ্য যেগুলিকে লক্ষ্য করে এমন ডিভাইসগুলিতে Google Play পরিষেবাগুলি ইনস্টল করা আছে৷

যদি আপনার অ্যাপটি Google Play পরিষেবা ব্যবহার করে, তাহলে নিশ্চিত করুন যে আপনার অ্যাপটি ইনস্টল করা ডিভাইসে এটি আপডেট করা আছে। UI থ্রেডের বাইরে, অ্যাসিঙ্ক্রোনাসভাবে চেকটি সম্পাদন করুন। ডিভাইসটি আপ টু ডেট না হলে, একটি অনুমোদন ত্রুটি ট্রিগার করুন।

আপনার অ্যাপটি যে ডিভাইসে ইনস্টল করা আছে সেখানে Google Play পরিষেবাগুলি আপ টু ডেট আছে কিনা তা নির্ধারণ করতে, SSL শোষণের বিরুদ্ধে সুরক্ষার জন্য আপনার নিরাপত্তা প্রদানকারীকে আপডেট করার বিষয়ে নির্দেশিত পদক্ষেপগুলি অনুসরণ করুন৷

সম্পর্কিত তথ্য:

সমস্ত অ্যাপ নির্ভরতা আপডেট করুন

আপনার অ্যাপ স্থাপন করার আগে, নিশ্চিত করুন যে সমস্ত লাইব্রেরি, SDK এবং অন্যান্য নির্ভরতা আপ টু ডেট আছে:

  • Android SDK-এর মতো প্রথম-পক্ষ নির্ভরতার জন্য, Android স্টুডিওতে পাওয়া আপডেট করার সরঞ্জামগুলি ব্যবহার করুন, যেমন SDK ম্যানেজার
  • তৃতীয় পক্ষের নির্ভরতাগুলির জন্য, আপনার অ্যাপ ব্যবহার করে এমন লাইব্রেরিগুলির ওয়েবসাইটগুলি পরীক্ষা করুন এবং উপলব্ধ আপডেট এবং নিরাপত্তা প্যাচগুলি ইনস্টল করুন৷

সম্পর্কিত তথ্য: বিল্ড নির্ভরতা যোগ করুন

আরও তথ্য

কীভাবে আপনার অ্যাপকে আরও সুরক্ষিত করা যায় সে সম্পর্কে আরও জানতে, নিম্নলিখিত সংস্থানগুলি দেখুন:

,

আপনার অ্যাপকে আরও সুরক্ষিত করে আপনি ব্যবহারকারীর বিশ্বাস এবং ডিভাইসের অখণ্ডতা রক্ষা করতে সাহায্য করেন।

এই পৃষ্ঠাটি বেশ কয়েকটি সর্বোত্তম অনুশীলন উপস্থাপন করে যা আপনার অ্যাপের নিরাপত্তার উপর একটি উল্লেখযোগ্য, ইতিবাচক প্রভাব ফেলে।

নিরাপদ যোগাযোগ প্রয়োগ করুন

যখন আপনি আপনার অ্যাপ এবং অন্যান্য অ্যাপের মধ্যে বা আপনার অ্যাপ এবং কোনও ওয়েবসাইটের মধ্যে বিনিময় করা ডেটাকে সুরক্ষিত করেন, তখন আপনি আপনার অ্যাপের স্থায়িত্বকে উন্নত করেন এবং আপনার পাঠানো ও গ্রহণ করা ডেটাকে সুরক্ষিত করেন।

অ্যাপের মধ্যে যোগাযোগ রক্ষা করুন

আরও নিরাপদে অ্যাপগুলির মধ্যে যোগাযোগ করতে, একটি অ্যাপ চয়নকারী, স্বাক্ষর-ভিত্তিক অনুমতি এবং অ-রপ্তানিকৃত সামগ্রী প্রদানকারীদের সাথে অন্তর্নিহিত উদ্দেশ্যগুলি ব্যবহার করুন৷

একটি অ্যাপ চয়নকারী দেখান৷

যদি একটি অন্তর্নিহিত উদ্দেশ্য ব্যবহারকারীর ডিভাইসে কমপক্ষে দুটি সম্ভাব্য অ্যাপ চালু করতে পারে, তাহলে স্পষ্টভাবে একটি অ্যাপ চয়নকারী দেখান। এই মিথস্ক্রিয়া কৌশলটি ব্যবহারকারীদের তাদের বিশ্বাসযোগ্য একটি অ্যাপে সংবেদনশীল তথ্য স্থানান্তর করতে দেয়।

কোটলিন

val intent = Intent(Intent.ACTION_SEND)
val possibleActivitiesList: List<ResolveInfo> =
        packageManager.queryIntentActivities(intent, PackageManager.MATCH_ALL)

// Verify that an activity in at least two apps on the user's device
// can handle the intent. Otherwise, start the intent only if an app
// on the user's device can handle the intent.
if (possibleActivitiesList.size > 1) {

    // Create intent to show chooser.
    // Title is something similar to "Share this photo with."

    val chooser = resources.getString(R.string.chooser_title).let { title ->
        Intent.createChooser(intent, title)
    }
    startActivity(chooser)
} else if (intent.resolveActivity(packageManager) != null) {
    startActivity(intent)
}

জাভা

Intent intent = new Intent(Intent.ACTION_SEND);
List<ResolveInfo> possibleActivitiesList = getPackageManager()
        .queryIntentActivities(intent, PackageManager.MATCH_ALL);

// Verify that an activity in at least two apps on the user's device
// can handle the intent. Otherwise, start the intent only if an app
// on the user's device can handle the intent.
if (possibleActivitiesList.size() > 1) {

    // Create intent to show chooser.
    // Title is something similar to "Share this photo with."

    String title = getResources().getString(R.string.chooser_title);
    Intent chooser = Intent.createChooser(intent, title);
    startActivity(chooser);
} else if (intent.resolveActivity(getPackageManager()) != null) {
    startActivity(intent);
}

সম্পর্কিত তথ্য:

স্বাক্ষর-ভিত্তিক অনুমতি প্রয়োগ করুন

আপনার নিয়ন্ত্রণ বা মালিকানাধীন দুটি অ্যাপের মধ্যে ডেটা ভাগ করার সময়, স্বাক্ষর-ভিত্তিক অনুমতিগুলি ব্যবহার করুন৷ এই অনুমতিগুলির জন্য ব্যবহারকারীর নিশ্চিতকরণের প্রয়োজন হয় না এবং পরিবর্তে পরীক্ষা করে দেখুন যে ডেটা অ্যাক্সেস করা অ্যাপগুলি একই সাইনিং কী ব্যবহার করে সাইন করা হয়েছে। অতএব, এই অনুমতিগুলি আরও সুগমিত, নিরাপদ ব্যবহারকারীর অভিজ্ঞতা প্রদান করে।

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapp">
    <permission android:name="my_custom_permission_name"
                android:protectionLevel="signature" />

সম্পর্কিত তথ্য:

আপনার অ্যাপের বিষয়বস্তু প্রদানকারীদের অ্যাক্সেসের অনুমতি দিন

যদি না আপনি আপনার অ্যাপ থেকে ডেটা পাঠাতে চান এমন একটি ভিন্ন অ্যাপে যা আপনার নিজের নয়, স্পষ্টভাবে অন্য ডেভেলপারদের অ্যাপগুলিকে আপনার অ্যাপের ContentProvider অবজেক্ট অ্যাক্সেস করা থেকে বিরত রাখুন। এই সেটিংটি বিশেষভাবে গুরুত্বপূর্ণ যদি আপনার অ্যাপটি Android 4.1.1 (API লেভেল 16) বা তার কম সংস্করণে চলমান ডিভাইসগুলিতে ইনস্টল করা যায়, কারণ <provider> উপাদানটির android:exported বৈশিষ্ট্যটি Android-এর সেই সংস্করণগুলিতে ডিফল্টরূপে true

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapp">
    <application ... >
        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="com.example.myapp.fileprovider"
            ...
            android:exported="false">
            <!-- Place child elements of <provider> here. -->
        </provider>
        ...
    </application>
</manifest>

সংবেদনশীল তথ্য দেখানোর আগে শংসাপত্রের জন্য জিজ্ঞাসা করুন

ব্যবহারকারীদের কাছ থেকে শংসাপত্রের অনুরোধ করার সময় যাতে তারা আপনার অ্যাপে সংবেদনশীল তথ্য বা প্রিমিয়াম সামগ্রী অ্যাক্সেস করতে পারে, একটি পিন/পাসওয়ার্ড/প্যাটার্ন বা বায়োমেট্রিক শংসাপত্রের জন্য জিজ্ঞাসা করুন, যেমন মুখ শনাক্তকরণ বা আঙুলের ছাপ শনাক্তকরণ৷

কীভাবে বায়োমেট্রিক শংসাপত্রের অনুরোধ করতে হয় সে সম্পর্কে আরও জানতে, বায়োমেট্রিক প্রমাণীকরণ সম্পর্কে নির্দেশিকাটি দেখুন।

নেটওয়ার্ক নিরাপত্তা ব্যবস্থা প্রয়োগ করুন

নিম্নলিখিত বিভাগগুলি বর্ণনা করে যে আপনি কীভাবে আপনার অ্যাপের নেটওয়ার্ক নিরাপত্তা উন্নত করতে পারেন৷

TLS ট্রাফিক ব্যবহার করুন

যদি আপনার অ্যাপটি এমন একটি ওয়েব সার্ভারের সাথে যোগাযোগ করে যার একটি সুপরিচিত, বিশ্বস্ত সার্টিফিকেট অথরিটি (CA) দ্বারা জারি করা শংসাপত্র রয়েছে, তাহলে নিম্নোক্ত মত একটি HTTPS অনুরোধ ব্যবহার করুন:

কোটলিন

val url = URL("https://www.google.com")
val urlConnection = url.openConnection() as HttpsURLConnection
urlConnection.connect()
urlConnection.inputStream.use {
    ...
}

জাভা

URL url = new URL("https://www.google.com");
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
urlConnection.connect();
InputStream in = urlConnection.getInputStream();

একটি নেটওয়ার্ক নিরাপত্তা কনফিগারেশন যোগ করুন

যদি আপনার অ্যাপ নতুন বা কাস্টম CA ব্যবহার করে, তাহলে আপনি একটি কনফিগারেশন ফাইলে আপনার নেটওয়ার্কের নিরাপত্তা সেটিংস ঘোষণা করতে পারেন। এই প্রক্রিয়াটি আপনাকে কোনো অ্যাপ কোড পরিবর্তন না করেই কনফিগারেশন তৈরি করতে দেয়।

আপনার অ্যাপে একটি নেটওয়ার্ক নিরাপত্তা কনফিগারেশন ফাইল যোগ করতে, এই পদক্ষেপগুলি অনুসরণ করুন:

  1. আপনার অ্যাপের ম্যানিফেস্টে কনফিগারেশন ঘোষণা করুন:
  2. <manifest ... >
        <application
            android:networkSecurityConfig="@xml/network_security_config"
            ... >
            <!-- Place child elements of <application> element here. -->
        </application>
    </manifest>
  3. res/xml/network_security_config.xml এ অবস্থিত একটি XML রিসোর্স ফাইল যোগ করুন।

    নির্দিষ্ট করুন যে নির্দিষ্ট ডোমেনে সমস্ত ট্র্যাফিক অবশ্যই ক্লিয়ার-টেক্সট অক্ষম করে HTTPS ব্যবহার করবে:

    <network-security-config>
        <domain-config cleartextTrafficPermitted="false">
            <domain includeSubdomains="true">secure.example.com</domain>
            ...
        </domain-config>
    </network-security-config>

    বিকাশ প্রক্রিয়া চলাকালীন, আপনি ব্যবহারকারী-ইনস্টল করা শংসাপত্রগুলিকে স্পষ্টভাবে অনুমতি দিতে <debug-overrides> উপাদান ব্যবহার করতে পারেন। এই উপাদানটি অ্যাপের রিলিজ কনফিগারেশনকে প্রভাবিত না করেই ডিবাগিং এবং পরীক্ষার সময় আপনার অ্যাপের নিরাপত্তা-সমালোচনামূলক বিকল্পগুলিকে ওভাররাইড করে। নিম্নলিখিত স্নিপেটটি আপনার অ্যাপের নেটওয়ার্ক নিরাপত্তা কনফিগারেশন XML ফাইলে এই উপাদানটিকে কীভাবে সংজ্ঞায়িত করতে হয় তা দেখায়:

    <network-security-config>
        <debug-overrides>
            <trust-anchors>
                <certificates src="user" />
            </trust-anchors>
        </debug-overrides>
    </network-security-config>

সম্পর্কিত তথ্য: নেটওয়ার্ক নিরাপত্তা কনফিগারেশন

আপনার নিজের ট্রাস্ট ম্যানেজার তৈরি করুন

আপনার TLS পরীক্ষকের প্রতিটি শংসাপত্র গ্রহণ করা উচিত নয়। নিম্নলিখিত শর্তগুলির মধ্যে একটি আপনার ব্যবহারের ক্ষেত্রে প্রযোজ্য হলে আপনাকে একটি ট্রাস্ট ম্যানেজার সেট আপ করতে এবং সমস্ত TLS সতর্কতাগুলি পরিচালনা করতে হতে পারে:

  • আপনি একটি ওয়েব সার্ভারের সাথে যোগাযোগ করছেন যাতে একটি নতুন বা কাস্টম CA দ্বারা স্বাক্ষরিত একটি শংসাপত্র রয়েছে৷
  • আপনি যে ডিভাইসটি ব্যবহার করছেন তার দ্বারা সেই CA বিশ্বাসযোগ্য নয়৷
  • আপনি একটি নেটওয়ার্ক নিরাপত্তা কনফিগারেশন ব্যবহার করতে পারবেন না৷

এই পদক্ষেপগুলি কীভাবে সম্পূর্ণ করবেন সে সম্পর্কে আরও জানতে, একটি অজানা শংসাপত্র কর্তৃপক্ষ পরিচালনার বিষয়ে আলোচনাটি দেখুন।

সম্পর্কিত তথ্য:

WebView অবজেক্ট সাবধানে ব্যবহার করুন

আপনার অ্যাপের WebView অবজেক্টগুলি ব্যবহারকারীদের এমন সাইটগুলিতে নেভিগেট করতে দেয় না যা আপনার নিয়ন্ত্রণের বাইরে। যখনই সম্ভব, আপনার অ্যাপের WebView অবজেক্ট দ্বারা লোড করা সামগ্রীকে সীমাবদ্ধ করতে অনুমতি তালিকা ব্যবহার করুন।

উপরন্তু, জাভাস্ক্রিপ্ট ইন্টারফেস সমর্থন সক্ষম করবেন না যদি না আপনি সম্পূর্ণরূপে আপনার অ্যাপের WebView অবজেক্টের বিষয়বস্তু নিয়ন্ত্রণ এবং বিশ্বাস করেন।

HTML বার্তা চ্যানেল ব্যবহার করুন

যদি আপনার অ্যাপ অবশ্যই Android 6.0 (API লেভেল 23) এবং তার উপরে চলমান ডিভাইসগুলিতে JavaScript ইন্টারফেস সমর্থন ব্যবহার করে, তাহলে নিম্নলিখিত কোড স্নিপেটে দেখানো হিসাবে ওয়েবসাইট এবং আপনার অ্যাপের মধ্যে যোগাযোগের পরিবর্তে HTML বার্তা চ্যানেলগুলি ব্যবহার করুন:

কোটলিন

val myWebView: WebView = findViewById(R.id.webview)

// channel[0] and channel[1] represent the two ports.
// They are already entangled with each other and have been started.
val channel: Array<out WebMessagePort> = myWebView.createWebMessageChannel()

// Create handler for channel[0] to receive messages.
channel[0].setWebMessageCallback(object : WebMessagePort.WebMessageCallback() {

    override fun onMessage(port: WebMessagePort, message: WebMessage) {
        Log.d(TAG, "On port $port, received this message: $message")
    }
})

// Send a message from channel[1] to channel[0].
channel[1].postMessage(WebMessage("My secure message"))

জাভা

WebView myWebView = (WebView) findViewById(R.id.webview);

// channel[0] and channel[1] represent the two ports.
// They are already entangled with each other and have been started.
WebMessagePort[] channel = myWebView.createWebMessageChannel();

// Create handler for channel[0] to receive messages.
channel[0].setWebMessageCallback(new WebMessagePort.WebMessageCallback() {
    @Override
    public void onMessage(WebMessagePort port, WebMessage message) {
         Log.d(TAG, "On port " + port + ", received this message: " + message);
    }
});

// Send a message from channel[1] to channel[0].
channel[1].postMessage(new WebMessage("My secure message"));

সম্পর্কিত তথ্য:

সঠিক অনুমতি প্রদান করুন

আপনার অ্যাপটি সঠিকভাবে কাজ করার জন্য প্রয়োজনীয় ন্যূনতম সংখ্যক অনুমতির অনুরোধ করুন। যখন সম্ভব, আপনার অ্যাপের আর প্রয়োজন না হলে অনুমতি ত্যাগ করুন।

অনুমতি স্থগিত করতে উদ্দেশ্য ব্যবহার করুন

যখনই সম্ভব, অন্য অ্যাপে সম্পন্ন করা যেতে পারে এমন একটি অ্যাকশন সম্পূর্ণ করার জন্য আপনার অ্যাপে অনুমতি যোগ করবেন না। পরিবর্তে, ইতিমধ্যেই প্রয়োজনীয় অনুমতি রয়েছে এমন একটি ভিন্ন অ্যাপে অনুরোধটি পিছিয়ে দেওয়ার জন্য একটি উদ্দেশ্য ব্যবহার করুন।

নিম্নলিখিত উদাহরণটি দেখায় যে কীভাবে ব্যবহারকারীদের READ_CONTACTS এবং WRITE_CONTACTS অনুমতির অনুরোধ করার পরিবর্তে একটি পরিচিতি অ্যাপে নির্দেশিত করতে একটি অভিপ্রায় ব্যবহার করতে হয়:

কোটলিন

// Delegates the responsibility of creating the contact to a contacts app,
// which has already been granted the appropriate WRITE_CONTACTS permission.
Intent(Intent.ACTION_INSERT).apply {
    type = ContactsContract.Contacts.CONTENT_TYPE
}.also { intent ->
    // Make sure that the user has a contacts app installed on their device.
    intent.resolveActivity(packageManager)?.run {
        startActivity(intent)
    }
}

জাভা

// Delegates the responsibility of creating the contact to a contacts app,
// which has already been granted the appropriate WRITE_CONTACTS permission.
Intent insertContactIntent = new Intent(Intent.ACTION_INSERT);
insertContactIntent.setType(ContactsContract.Contacts.CONTENT_TYPE);

// Make sure that the user has a contacts app installed on their device.
if (insertContactIntent.resolveActivity(getPackageManager()) != null) {
    startActivity(insertContactIntent);
}

উপরন্তু, যদি আপনার অ্যাপটিকে ফাইল-ভিত্তিক I/O- যেমন সঞ্চয়স্থান অ্যাক্সেস করা বা একটি ফাইল বেছে নেওয়ার প্রয়োজন হয়- তবে এটির বিশেষ অনুমতির প্রয়োজন নেই কারণ সিস্টেমটি আপনার অ্যাপের হয়ে কাজগুলি সম্পূর্ণ করতে পারে। আরও ভাল, কোনও ব্যবহারকারী একটি নির্দিষ্ট ইউআরআই-তে সামগ্রী নির্বাচন করার পরে, কলিং অ্যাপটি নির্বাচিত সংস্থানের অনুমতি পায়।

সম্পর্কিত তথ্য:

অ্যাপ জুড়ে নিরাপদে ডেটা শেয়ার করুন

আরও নিরাপদ পদ্ধতিতে অন্যান্য অ্যাপের সাথে আপনার অ্যাপের বিষয়বস্তু শেয়ার করতে এই সবথেকে ভাল অভ্যাসগুলি অনুসরণ করুন:

  • প্রয়োজন অনুযায়ী শুধুমাত্র-পঠন বা শুধুমাত্র লেখার অনুমতি প্রয়োগ করুন।
  • FLAG_GRANT_READ_URI_PERMISSION এবং FLAG_GRANT_WRITE_URI_PERMISSION ফ্ল্যাগগুলি ব্যবহার করে ক্লায়েন্টদের ডেটাতে এককালীন অ্যাক্সেস প্রদান করুন৷
  • ডেটা শেয়ার করার সময়, content:// URIs ব্যবহার করুন, file:// URIs নয়। FileProvider এর উদাহরণগুলি আপনার জন্য এটি করে।

নিচের কোড স্নিপেটটি দেখায় কিভাবে ইউআরআই অনুমতি মঞ্জুর ফ্ল্যাগ ব্যবহার করতে হয় এবং একটি পৃথক পিডিএফ ভিউয়ার অ্যাপে একটি অ্যাপের পিডিএফ ফাইল প্রদর্শন করতে সামগ্রী প্রদানকারীর অনুমতি দেয়:

কোটলিন

// Create an Intent to launch a PDF viewer for a file owned by this app.
Intent(Intent.ACTION_VIEW).apply {
    data = Uri.parse("content://com.example/personal-info.pdf")

    // This flag gives the started app read access to the file.
    addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}.also { intent ->
    // Make sure that the user has a PDF viewer app installed on their device.
    intent.resolveActivity(packageManager)?.run {
        startActivity(intent)
    }
}

জাভা

// Create an Intent to launch a PDF viewer for a file owned by this app.
Intent viewPdfIntent = new Intent(Intent.ACTION_VIEW);
viewPdfIntent.setData(Uri.parse("content://com.example/personal-info.pdf"));

// This flag gives the started app read access to the file.
viewPdfIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

// Make sure that the user has a PDF viewer app installed on their device.
if (viewPdfIntent.resolveActivity(getPackageManager()) != null) {
    startActivity(viewPdfIntent);
}

দ্রষ্টব্য: লিখনযোগ্য অ্যাপ হোম ডিরেক্টরি থেকে ফাইলগুলি সম্পাদন করা একটি W^X লঙ্ঘন । এই কারণে, অবিশ্বস্ত অ্যাপগুলি যেগুলি Android 10 (API স্তর 29) এবং উচ্চতরকে লক্ষ্য করে তারা অ্যাপের হোম ডিরেক্টরির মধ্যে ফাইলগুলিতে exec() চালু করতে পারে না, শুধুমাত্র একটি অ্যাপের APK ফাইলের মধ্যে এমবেড করা বাইনারি কোড। এছাড়াও, যে অ্যাপগুলি Android 10 এবং উচ্চতরকে লক্ষ্য করে, সেগুলি মেমরিতে, dlopen() দিয়ে খোলা ফাইলগুলি থেকে এক্সিকিউটেবল কোড পরিবর্তন করতে পারে না৷ এতে টেক্সট রিলোকেশন সহ যেকোনও শেয়ার করা অবজেক্ট ( .so ) ফাইল অন্তর্ভুক্ত থাকে।

সম্পর্কিত তথ্য: android:grantUriPermissions

নিরাপদে ডেটা সংরক্ষণ করুন

যদিও আপনার অ্যাপের সংবেদনশীল ব্যবহারকারীর তথ্যে অ্যাক্সেসের প্রয়োজন হতে পারে, ব্যবহারকারীরা আপনার অ্যাপকে শুধুমাত্র তাদের ডেটাতে অ্যাক্সেস দেয় যদি তারা বিশ্বাস করে যে আপনি এটি সঠিকভাবে সুরক্ষিত রেখেছেন।

অভ্যন্তরীণ স্টোরেজের মধ্যে ব্যক্তিগত তথ্য সংরক্ষণ করুন

ডিভাইসের অভ্যন্তরীণ স্টোরেজের মধ্যে সমস্ত ব্যক্তিগত ব্যবহারকারীর ডেটা সঞ্চয় করুন, যা প্রতি অ্যাপে স্যান্ডবক্স করা হয়। আপনার অ্যাপকে এই ফাইলগুলি দেখার অনুমতির অনুরোধ করার প্রয়োজন নেই এবং অন্যান্য অ্যাপগুলি ফাইলগুলি অ্যাক্সেস করতে পারে না৷ একটি অতিরিক্ত নিরাপত্তা ব্যবস্থা হিসাবে, ব্যবহারকারী যখন একটি অ্যাপ আনইনস্টল করেন, তখন ডিভাইসটি অভ্যন্তরীণ স্টোরেজের মধ্যে অ্যাপটি সংরক্ষিত সমস্ত ফাইল মুছে দেয়।

নিম্নলিখিত কোড স্নিপেট অভ্যন্তরীণ সঞ্চয়স্থানে ডেটা লেখার একটি উপায় প্রদর্শন করে:

কোটলিন

// Creates a file with this name, or replaces an existing file
// that has the same name. Note that the file name cannot contain
// path separators.
val FILE_NAME = "sensitive_info.txt"
val fileContents = "This is some top-secret information!"
File(filesDir, FILE_NAME).bufferedWriter().use { writer ->
    writer.write(fileContents)
}

জাভা

// Creates a file with this name, or replaces an existing file
// that has the same name. Note that the file name cannot contain
// path separators.
final String FILE_NAME = "sensitive_info.txt";
String fileContents = "This is some top-secret information!";
try (BufferedWriter writer =
             new BufferedWriter(new FileWriter(new File(getFilesDir(), FILE_NAME)))) {
    writer.write(fileContents);
} catch (IOException e) {
    // Handle exception.
}

নিম্নলিখিত কোড স্নিপেট অভ্যন্তরীণ সঞ্চয়স্থান থেকে ডেটা পড়া, বিপরীত অপারেশন দেখায়:

কোটলিন

val FILE_NAME = "sensitive_info.txt"
val contents = File(filesDir, FILE_NAME).bufferedReader().useLines { lines ->
    lines.fold("") { working, line ->
        "$working\n$line"
    }
}

জাভা

final String FILE_NAME = "sensitive_info.txt";
StringBuffer stringBuffer = new StringBuffer();
try (BufferedReader reader =
             new BufferedReader(new FileReader(new File(getFilesDir(), FILE_NAME)))) {

    String line = reader.readLine();
    while (line != null) {
        stringBuffer.append(line).append('\n');
        line = reader.readLine();
    }
} catch (IOException e) {
    // Handle exception.
}

সম্পর্কিত তথ্য:

ব্যবহারের ক্ষেত্রের উপর ভিত্তি করে বাহ্যিক সঞ্চয়স্থানে ডেটা সংরক্ষণ করুন

বড়, অ-সংবেদনশীল ফাইলগুলির জন্য বাহ্যিক সঞ্চয়স্থান ব্যবহার করুন যা আপনার অ্যাপের জন্য নির্দিষ্ট এবং সেইসাথে আপনার অ্যাপ অন্যান্য অ্যাপের সাথে শেয়ার করা ফাইলগুলির জন্য। আপনি যে নির্দিষ্ট APIগুলি ব্যবহার করেন তা নির্ভর করে আপনার অ্যাপটি অ্যাপ-নির্দিষ্ট ফাইলগুলি অ্যাক্সেস করতে বা শেয়ার করা ফাইলগুলি অ্যাক্সেস করার জন্য ডিজাইন করা হয়েছে কিনা তার উপর।

যদি কোনো ফাইলে ব্যক্তিগত বা সংবেদনশীল তথ্য না থাকে কিন্তু শুধুমাত্র আপনার অ্যাপে ব্যবহারকারীকে মূল্য প্রদান করে, তাহলে ফাইলটিকে এক্সটার্নাল স্টোরেজে একটি অ্যাপ-নির্দিষ্ট ডিরেক্টরিতে সংরক্ষণ করুন।

যদি আপনার অ্যাপের এমন কোনো ফাইল অ্যাক্সেস বা স্টোর করার প্রয়োজন হয় যা অন্য অ্যাপের মান প্রদান করে, তাহলে আপনার ব্যবহারের ক্ষেত্রে নির্ভর করে নিম্নলিখিত APIগুলির মধ্যে একটি ব্যবহার করুন:

স্টোরেজ ভলিউমের প্রাপ্যতা পরীক্ষা করুন

যদি আপনার অ্যাপটি একটি অপসারণযোগ্য বাহ্যিক স্টোরেজ ডিভাইসের সাথে ইন্টারঅ্যাক্ট করে, তাহলে মনে রাখবেন যে ব্যবহারকারী স্টোরেজ ডিভাইসটি সরিয়ে ফেলতে পারে যখন আপনার অ্যাপটি অ্যাক্সেস করার চেষ্টা করছে। স্টোরেজ ডিভাইস উপলব্ধ কিনা তা যাচাই করতে যুক্তি অন্তর্ভুক্ত করুন।

ডেটার বৈধতা পরীক্ষা করুন

যদি আপনার অ্যাপটি বাহ্যিক স্টোরেজ থেকে ডেটা ব্যবহার করে, তবে নিশ্চিত করুন যে ডেটার বিষয়বস্তুগুলি দূষিত বা সংশোধন করা হয়নি। স্থিতিশীল বিন্যাসে আর নেই এমন ফাইলগুলি পরিচালনা করার জন্য যুক্তি অন্তর্ভুক্ত করুন।

নিম্নলিখিত কোড স্নিপেটে একটি হ্যাশ যাচাইকারীর উদাহরণ রয়েছে:

কোটলিন

val hash = calculateHash(stream)
// Store "expectedHash" in a secure location.
if (hash == expectedHash) {
    // Work with the content.
}

// Calculating the hash code can take quite a bit of time, so it shouldn't
// be done on the main thread.
suspend fun calculateHash(stream: InputStream): String {
    return withContext(Dispatchers.IO) {
        val digest = MessageDigest.getInstance("SHA-512")
        val digestStream = DigestInputStream(stream, digest)
        while (digestStream.read() != -1) {
            // The DigestInputStream does the work; nothing for us to do.
        }
        digest.digest().joinToString(":") { "%02x".format(it) }
    }
}

জাভা

Executor threadPoolExecutor = Executors.newFixedThreadPool(4);
private interface HashCallback {
    void onHashCalculated(@Nullable String hash);
}

boolean hashRunning = calculateHash(inputStream, threadPoolExecutor, hash -> {
    if (Objects.equals(hash, expectedHash)) {
        // Work with the content.
    }
});

if (!hashRunning) {
    // There was an error setting up the hash function.
}

private boolean calculateHash(@NonNull InputStream stream,
                              @NonNull Executor executor,
                              @NonNull HashCallback hashCallback) {
    final MessageDigest digest;
    try {
        digest = MessageDigest.getInstance("SHA-512");
    } catch (NoSuchAlgorithmException nsa) {
        return false;
    }

    // Calculating the hash code can take quite a bit of time, so it shouldn't
    // be done on the main thread.
    executor.execute(() -> {
        String hash;
        try (DigestInputStream digestStream =
                new DigestInputStream(stream, digest)) {
            while (digestStream.read() != -1) {
                // The DigestInputStream does the work; nothing for us to do.
            }
            StringBuilder builder = new StringBuilder();
            for (byte aByte : digest.digest()) {
                builder.append(String.format("%02x", aByte)).append(':');
            }
            hash = builder.substring(0, builder.length() - 1);
        } catch (IOException e) {
            hash = null;
        }

        final String calculatedHash = hash;
        runOnUiThread(() -> hashCallback.onHashCalculated(calculatedHash));
    });
    return true;
}

ক্যাশে ফাইলগুলিতে শুধুমাত্র অ-সংবেদনশীল ডেটা সংরক্ষণ করুন

অ-সংবেদনশীল অ্যাপ ডেটাতে দ্রুত অ্যাক্সেস প্রদান করতে, এটি ডিভাইসের ক্যাশে সংরক্ষণ করুন। 1 MB এর চেয়ে বড় ক্যাশেগুলির জন্য, getExternalCacheDir() ব্যবহার করুন। 1 MB বা ছোট ক্যাশেগুলির জন্য, getCacheDir() ব্যবহার করুন৷ উভয় পদ্ধতিই আপনাকে File অবজেক্ট প্রদান করে যাতে আপনার অ্যাপের ক্যাশে করা ডেটা থাকে।

নিম্নলিখিত কোড স্নিপেট দেখায় যে আপনার অ্যাপ সম্প্রতি ডাউনলোড করা একটি ফাইল কীভাবে ক্যাশে করবেন:

কোটলিন

val cacheFile = File(myDownloadedFileUri).let { fileToCache ->
    File(cacheDir.path, fileToCache.name)
}

জাভা

File cacheDir = getCacheDir();
File fileToCache = new File(myDownloadedFileUri);
String fileToCacheName = fileToCache.getName();
File cacheFile = new File(cacheDir.getPath(), fileToCacheName);

দ্রষ্টব্য: আপনি শেয়ার্ড স্টোরেজের মধ্যে আপনার অ্যাপের ক্যাশে রাখার জন্য getExternalCacheDir() ব্যবহার করলে, আপনার অ্যাপ চলাকালীন ব্যবহারকারী এই স্টোরেজ ধারণকারী মিডিয়া বের করে দিতে পারে। এই ব্যবহারকারীর আচরণের কারণে ক্যাশে মিসকে সুন্দরভাবে পরিচালনা করার জন্য যুক্তি অন্তর্ভুক্ত করুন।

সতর্কতা: এই ফাইলগুলিতে কোন নিরাপত্তা বলবৎ নেই। তাই, যেকোন অ্যাপ যেটি Android 10 (API লেভেল 29) বা তার নিচের দিকে লক্ষ্য করে এবং WRITE_EXTERNAL_STORAGE অনুমতি আছে তারা এই ক্যাশের বিষয়বস্তু অ্যাক্সেস করতে পারে।

সম্পর্কিত তথ্য: ডেটা এবং ফাইল স্টোরেজ ওভারভিউ

ব্যক্তিগত মোডে SharedPreferences ব্যবহার করুন

আপনার অ্যাপের SharedPreferences অবজেক্ট তৈরি বা অ্যাক্সেস করতে getSharedPreferences() ব্যবহার করার সময়, MODE_PRIVATE ব্যবহার করুন। এইভাবে, শুধুমাত্র আপনার অ্যাপ শেয়ার করা পছন্দ ফাইলের মধ্যে তথ্য অ্যাক্সেস করতে পারে।

আপনি যদি সমস্ত অ্যাপ জুড়ে ডেটা ভাগ করতে চান, তাহলে SharedPreferences অবজেক্ট ব্যবহার করবেন না। পরিবর্তে, অ্যাপ্লিকেশানগুলিতে নিরাপদে ডেটা ভাগ করতে পদক্ষেপগুলি অনুসরণ করুন৷

সিকিউরিটি লাইব্রেরি এনক্রিপ্টেড শেয়ারডপ্রেফারেন্স ক্লাসও প্রদান করে যা শেয়ারডপ্রেফারেন্স ক্লাসকে মোড়ানো হয় এবং কী এবং মানগুলি স্বয়ংক্রিয়ভাবে এনক্রিপ্ট করে।

সম্পর্কিত তথ্য:

পরিষেবা এবং নির্ভরতা আপ টু ডেট রাখুন

বেশিরভাগ অ্যাপ বিশেষায়িত কাজগুলি সম্পূর্ণ করতে বাহ্যিক লাইব্রেরি এবং ডিভাইস সিস্টেম তথ্য ব্যবহার করে। আপনার অ্যাপের নির্ভরতা আপ টু ডেট রেখে, আপনি যোগাযোগের এই পয়েন্টগুলিকে আরও সুরক্ষিত করে তোলেন৷

Google Play পরিষেবা নিরাপত্তা প্রদানকারী চেক করুন

দ্রষ্টব্য: এই বিভাগটি শুধুমাত্র এমন অ্যাপগুলির জন্য প্রযোজ্য যেগুলিকে লক্ষ্য করে এমন ডিভাইসগুলিতে Google Play পরিষেবাগুলি ইনস্টল করা আছে৷

যদি আপনার অ্যাপটি Google Play পরিষেবা ব্যবহার করে, তাহলে নিশ্চিত করুন যে আপনার অ্যাপটি ইনস্টল করা ডিভাইসে এটি আপডেট করা আছে। UI থ্রেডের বাইরে, অ্যাসিঙ্ক্রোনাসভাবে চেকটি সম্পাদন করুন। ডিভাইসটি আপ টু ডেট না হলে, একটি অনুমোদন ত্রুটি ট্রিগার করুন।

আপনার অ্যাপটি যে ডিভাইসে ইনস্টল করা আছে সেখানে Google Play পরিষেবাগুলি আপ টু ডেট আছে কিনা তা নির্ধারণ করতে, SSL শোষণের বিরুদ্ধে সুরক্ষার জন্য আপনার নিরাপত্তা প্রদানকারীকে আপডেট করার বিষয়ে নির্দেশিত পদক্ষেপগুলি অনুসরণ করুন৷

সম্পর্কিত তথ্য:

সমস্ত অ্যাপ নির্ভরতা আপডেট করুন

আপনার অ্যাপ স্থাপন করার আগে, নিশ্চিত করুন যে সমস্ত লাইব্রেরি, SDK এবং অন্যান্য নির্ভরতা আপ টু ডেট আছে:

  • Android SDK-এর মতো প্রথম-পক্ষ নির্ভরতার জন্য, Android স্টুডিওতে পাওয়া আপডেট করার সরঞ্জামগুলি ব্যবহার করুন, যেমন SDK ম্যানেজার
  • তৃতীয় পক্ষের নির্ভরতাগুলির জন্য, আপনার অ্যাপ ব্যবহার করে এমন লাইব্রেরিগুলির ওয়েবসাইটগুলি পরীক্ষা করুন এবং উপলব্ধ আপডেট এবং নিরাপত্তা প্যাচগুলি ইনস্টল করুন৷

সম্পর্কিত তথ্য: বিল্ড নির্ভরতা যোগ করুন

আরও তথ্য

কীভাবে আপনার অ্যাপকে আরও সুরক্ষিত করা যায় সে সম্পর্কে আরও জানতে, নিম্নলিখিত সংস্থানগুলি দেখুন:

,

আপনার অ্যাপকে আরও সুরক্ষিত করে আপনি ব্যবহারকারীর বিশ্বাস এবং ডিভাইসের অখণ্ডতা রক্ষা করতে সাহায্য করেন।

এই পৃষ্ঠাটি বেশ কয়েকটি সর্বোত্তম অনুশীলন উপস্থাপন করে যা আপনার অ্যাপের নিরাপত্তার উপর একটি উল্লেখযোগ্য, ইতিবাচক প্রভাব ফেলে।

নিরাপদ যোগাযোগ প্রয়োগ করুন

যখন আপনি আপনার অ্যাপ এবং অন্যান্য অ্যাপের মধ্যে বা আপনার অ্যাপ এবং কোনও ওয়েবসাইটের মধ্যে বিনিময় করা ডেটাকে সুরক্ষিত করেন, তখন আপনি আপনার অ্যাপের স্থায়িত্বকে উন্নত করেন এবং আপনার পাঠানো ও গ্রহণ করা ডেটাকে সুরক্ষিত করেন।

অ্যাপের মধ্যে যোগাযোগ রক্ষা করুন

আরও নিরাপদে অ্যাপগুলির মধ্যে যোগাযোগ করতে, একটি অ্যাপ চয়নকারী, স্বাক্ষর-ভিত্তিক অনুমতি এবং অ-রপ্তানিকৃত সামগ্রী প্রদানকারীদের সাথে অন্তর্নিহিত উদ্দেশ্যগুলি ব্যবহার করুন৷

একটি অ্যাপ চয়নকারী দেখান৷

যদি একটি অন্তর্নিহিত উদ্দেশ্য ব্যবহারকারীর ডিভাইসে কমপক্ষে দুটি সম্ভাব্য অ্যাপ চালু করতে পারে, তাহলে স্পষ্টভাবে একটি অ্যাপ চয়নকারী দেখান। এই মিথস্ক্রিয়া কৌশলটি ব্যবহারকারীদের তাদের বিশ্বাসযোগ্য একটি অ্যাপে সংবেদনশীল তথ্য স্থানান্তর করতে দেয়।

কোটলিন

val intent = Intent(Intent.ACTION_SEND)
val possibleActivitiesList: List<ResolveInfo> =
        packageManager.queryIntentActivities(intent, PackageManager.MATCH_ALL)

// Verify that an activity in at least two apps on the user's device
// can handle the intent. Otherwise, start the intent only if an app
// on the user's device can handle the intent.
if (possibleActivitiesList.size > 1) {

    // Create intent to show chooser.
    // Title is something similar to "Share this photo with."

    val chooser = resources.getString(R.string.chooser_title).let { title ->
        Intent.createChooser(intent, title)
    }
    startActivity(chooser)
} else if (intent.resolveActivity(packageManager) != null) {
    startActivity(intent)
}

জাভা

Intent intent = new Intent(Intent.ACTION_SEND);
List<ResolveInfo> possibleActivitiesList = getPackageManager()
        .queryIntentActivities(intent, PackageManager.MATCH_ALL);

// Verify that an activity in at least two apps on the user's device
// can handle the intent. Otherwise, start the intent only if an app
// on the user's device can handle the intent.
if (possibleActivitiesList.size() > 1) {

    // Create intent to show chooser.
    // Title is something similar to "Share this photo with."

    String title = getResources().getString(R.string.chooser_title);
    Intent chooser = Intent.createChooser(intent, title);
    startActivity(chooser);
} else if (intent.resolveActivity(getPackageManager()) != null) {
    startActivity(intent);
}

সম্পর্কিত তথ্য:

স্বাক্ষর-ভিত্তিক অনুমতি প্রয়োগ করুন

আপনার নিয়ন্ত্রণ বা মালিকানাধীন দুটি অ্যাপের মধ্যে ডেটা ভাগ করার সময়, স্বাক্ষর-ভিত্তিক অনুমতিগুলি ব্যবহার করুন৷ এই অনুমতিগুলির জন্য ব্যবহারকারীর নিশ্চিতকরণের প্রয়োজন হয় না এবং পরিবর্তে পরীক্ষা করে দেখুন যে ডেটা অ্যাক্সেস করা অ্যাপগুলি একই সাইনিং কী ব্যবহার করে সাইন করা হয়েছে। অতএব, এই অনুমতিগুলি আরও সুগমিত, নিরাপদ ব্যবহারকারীর অভিজ্ঞতা প্রদান করে।

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapp">
    <permission android:name="my_custom_permission_name"
                android:protectionLevel="signature" />

সম্পর্কিত তথ্য:

আপনার অ্যাপের বিষয়বস্তু প্রদানকারীদের অ্যাক্সেসের অনুমতি দিন

যদি না আপনি আপনার অ্যাপ থেকে ডেটা পাঠাতে চান এমন একটি ভিন্ন অ্যাপে যা আপনার নিজের নয়, স্পষ্টভাবে অন্য ডেভেলপারদের অ্যাপগুলিকে আপনার অ্যাপের ContentProvider অবজেক্ট অ্যাক্সেস করা থেকে বিরত রাখুন। এই সেটিংটি বিশেষভাবে গুরুত্বপূর্ণ যদি আপনার অ্যাপটি Android 4.1.1 (API লেভেল 16) বা তার কম সংস্করণে চলমান ডিভাইসগুলিতে ইনস্টল করা যায়, কারণ <provider> উপাদানটির android:exported বৈশিষ্ট্যটি Android-এর সেই সংস্করণগুলিতে ডিফল্টরূপে true

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapp">
    <application ... >
        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="com.example.myapp.fileprovider"
            ...
            android:exported="false">
            <!-- Place child elements of <provider> here. -->
        </provider>
        ...
    </application>
</manifest>

সংবেদনশীল তথ্য দেখানোর আগে শংসাপত্রের জন্য জিজ্ঞাসা করুন

ব্যবহারকারীদের কাছ থেকে শংসাপত্রের অনুরোধ করার সময় যাতে তারা আপনার অ্যাপে সংবেদনশীল তথ্য বা প্রিমিয়াম সামগ্রী অ্যাক্সেস করতে পারে, একটি পিন/পাসওয়ার্ড/প্যাটার্ন বা বায়োমেট্রিক শংসাপত্রের জন্য জিজ্ঞাসা করুন, যেমন মুখ শনাক্তকরণ বা আঙুলের ছাপ শনাক্তকরণ৷

কীভাবে বায়োমেট্রিক শংসাপত্রের অনুরোধ করতে হয় সে সম্পর্কে আরও জানতে, বায়োমেট্রিক প্রমাণীকরণ সম্পর্কে নির্দেশিকাটি দেখুন।

নেটওয়ার্ক নিরাপত্তা ব্যবস্থা প্রয়োগ করুন

নিম্নলিখিত বিভাগগুলি বর্ণনা করে যে আপনি কীভাবে আপনার অ্যাপের নেটওয়ার্ক নিরাপত্তা উন্নত করতে পারেন৷

TLS ট্রাফিক ব্যবহার করুন

যদি আপনার অ্যাপটি এমন একটি ওয়েব সার্ভারের সাথে যোগাযোগ করে যার একটি সুপরিচিত, বিশ্বস্ত সার্টিফিকেট অথরিটি (CA) দ্বারা জারি করা শংসাপত্র রয়েছে, তাহলে নিম্নোক্ত মত একটি HTTPS অনুরোধ ব্যবহার করুন:

কোটলিন

val url = URL("https://www.google.com")
val urlConnection = url.openConnection() as HttpsURLConnection
urlConnection.connect()
urlConnection.inputStream.use {
    ...
}

জাভা

URL url = new URL("https://www.google.com");
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
urlConnection.connect();
InputStream in = urlConnection.getInputStream();

একটি নেটওয়ার্ক নিরাপত্তা কনফিগারেশন যোগ করুন

যদি আপনার অ্যাপ নতুন বা কাস্টম CA ব্যবহার করে, তাহলে আপনি একটি কনফিগারেশন ফাইলে আপনার নেটওয়ার্কের নিরাপত্তা সেটিংস ঘোষণা করতে পারেন। এই প্রক্রিয়াটি আপনাকে কোনো অ্যাপ কোড পরিবর্তন না করেই কনফিগারেশন তৈরি করতে দেয়।

আপনার অ্যাপে একটি নেটওয়ার্ক নিরাপত্তা কনফিগারেশন ফাইল যোগ করতে, এই পদক্ষেপগুলি অনুসরণ করুন:

  1. আপনার অ্যাপের ম্যানিফেস্টে কনফিগারেশন ঘোষণা করুন:
  2. <manifest ... >
        <application
            android:networkSecurityConfig="@xml/network_security_config"
            ... >
            <!-- Place child elements of <application> element here. -->
        </application>
    </manifest>
  3. res/xml/network_security_config.xml এ অবস্থিত একটি XML রিসোর্স ফাইল যোগ করুন।

    নির্দিষ্ট করুন যে নির্দিষ্ট ডোমেনে সমস্ত ট্র্যাফিক অবশ্যই ক্লিয়ার-টেক্সট অক্ষম করে HTTPS ব্যবহার করবে:

    <network-security-config>
        <domain-config cleartextTrafficPermitted="false">
            <domain includeSubdomains="true">secure.example.com</domain>
            ...
        </domain-config>
    </network-security-config>

    বিকাশ প্রক্রিয়া চলাকালীন, আপনি ব্যবহারকারী-ইনস্টল করা শংসাপত্রগুলিকে স্পষ্টভাবে অনুমতি দিতে <debug-overrides> উপাদান ব্যবহার করতে পারেন। এই উপাদানটি অ্যাপের রিলিজ কনফিগারেশনকে প্রভাবিত না করেই ডিবাগিং এবং পরীক্ষার সময় আপনার অ্যাপের নিরাপত্তা-সমালোচনামূলক বিকল্পগুলিকে ওভাররাইড করে। নিম্নলিখিত স্নিপেটটি আপনার অ্যাপের নেটওয়ার্ক নিরাপত্তা কনফিগারেশন XML ফাইলে এই উপাদানটিকে কীভাবে সংজ্ঞায়িত করতে হয় তা দেখায়:

    <network-security-config>
        <debug-overrides>
            <trust-anchors>
                <certificates src="user" />
            </trust-anchors>
        </debug-overrides>
    </network-security-config>

সম্পর্কিত তথ্য: নেটওয়ার্ক নিরাপত্তা কনফিগারেশন

আপনার নিজের ট্রাস্ট ম্যানেজার তৈরি করুন

আপনার TLS পরীক্ষকের প্রতিটি শংসাপত্র গ্রহণ করা উচিত নয়। নিম্নলিখিত শর্তগুলির মধ্যে একটি আপনার ব্যবহারের ক্ষেত্রে প্রযোজ্য হলে আপনাকে একটি ট্রাস্ট ম্যানেজার সেট আপ করতে এবং সমস্ত TLS সতর্কতাগুলি পরিচালনা করতে হতে পারে:

  • আপনি একটি ওয়েব সার্ভারের সাথে যোগাযোগ করছেন যাতে একটি নতুন বা কাস্টম CA দ্বারা স্বাক্ষরিত একটি শংসাপত্র রয়েছে৷
  • আপনি যে ডিভাইসটি ব্যবহার করছেন তার দ্বারা সেই CA বিশ্বাসযোগ্য নয়৷
  • আপনি একটি নেটওয়ার্ক নিরাপত্তা কনফিগারেশন ব্যবহার করতে পারবেন না৷

এই পদক্ষেপগুলি কীভাবে সম্পূর্ণ করবেন সে সম্পর্কে আরও জানতে, একটি অজানা শংসাপত্র কর্তৃপক্ষ পরিচালনার বিষয়ে আলোচনাটি দেখুন।

সম্পর্কিত তথ্য:

WebView অবজেক্ট সাবধানে ব্যবহার করুন

আপনার অ্যাপের WebView অবজেক্টগুলি ব্যবহারকারীদের এমন সাইটগুলিতে নেভিগেট করতে দেয় না যা আপনার নিয়ন্ত্রণের বাইরে। যখনই সম্ভব, আপনার অ্যাপের WebView অবজেক্ট দ্বারা লোড করা সামগ্রীকে সীমাবদ্ধ করতে অনুমতি তালিকা ব্যবহার করুন।

উপরন্তু, জাভাস্ক্রিপ্ট ইন্টারফেস সমর্থন সক্ষম করবেন না যদি না আপনি সম্পূর্ণরূপে আপনার অ্যাপের WebView অবজেক্টের বিষয়বস্তু নিয়ন্ত্রণ এবং বিশ্বাস করেন।

HTML বার্তা চ্যানেল ব্যবহার করুন

যদি আপনার অ্যাপ অবশ্যই Android 6.0 (API লেভেল 23) এবং তার উপরে চলমান ডিভাইসগুলিতে JavaScript ইন্টারফেস সমর্থন ব্যবহার করে, তাহলে নিম্নলিখিত কোড স্নিপেটে দেখানো হিসাবে ওয়েবসাইট এবং আপনার অ্যাপের মধ্যে যোগাযোগের পরিবর্তে HTML বার্তা চ্যানেলগুলি ব্যবহার করুন:

কোটলিন

val myWebView: WebView = findViewById(R.id.webview)

// channel[0] and channel[1] represent the two ports.
// They are already entangled with each other and have been started.
val channel: Array<out WebMessagePort> = myWebView.createWebMessageChannel()

// Create handler for channel[0] to receive messages.
channel[0].setWebMessageCallback(object : WebMessagePort.WebMessageCallback() {

    override fun onMessage(port: WebMessagePort, message: WebMessage) {
        Log.d(TAG, "On port $port, received this message: $message")
    }
})

// Send a message from channel[1] to channel[0].
channel[1].postMessage(WebMessage("My secure message"))

জাভা

WebView myWebView = (WebView) findViewById(R.id.webview);

// channel[0] and channel[1] represent the two ports.
// They are already entangled with each other and have been started.
WebMessagePort[] channel = myWebView.createWebMessageChannel();

// Create handler for channel[0] to receive messages.
channel[0].setWebMessageCallback(new WebMessagePort.WebMessageCallback() {
    @Override
    public void onMessage(WebMessagePort port, WebMessage message) {
         Log.d(TAG, "On port " + port + ", received this message: " + message);
    }
});

// Send a message from channel[1] to channel[0].
channel[1].postMessage(new WebMessage("My secure message"));

সম্পর্কিত তথ্য:

সঠিক অনুমতি প্রদান করুন

আপনার অ্যাপটি সঠিকভাবে কাজ করার জন্য প্রয়োজনীয় ন্যূনতম সংখ্যক অনুমতির অনুরোধ করুন। যখন সম্ভব, আপনার অ্যাপের আর প্রয়োজন না হলে অনুমতি ত্যাগ করুন।

অনুমতি স্থগিত করতে উদ্দেশ্য ব্যবহার করুন

যখনই সম্ভব, অন্য অ্যাপে সম্পন্ন করা যেতে পারে এমন একটি অ্যাকশন সম্পূর্ণ করার জন্য আপনার অ্যাপে অনুমতি যোগ করবেন না। পরিবর্তে, ইতিমধ্যেই প্রয়োজনীয় অনুমতি রয়েছে এমন একটি ভিন্ন অ্যাপে অনুরোধটি পিছিয়ে দেওয়ার জন্য একটি উদ্দেশ্য ব্যবহার করুন।

নিম্নলিখিত উদাহরণটি দেখায় যে কীভাবে ব্যবহারকারীদের READ_CONTACTS এবং WRITE_CONTACTS অনুমতির অনুরোধ করার পরিবর্তে একটি পরিচিতি অ্যাপে নির্দেশিত করতে একটি অভিপ্রায় ব্যবহার করতে হয়:

কোটলিন

// Delegates the responsibility of creating the contact to a contacts app,
// which has already been granted the appropriate WRITE_CONTACTS permission.
Intent(Intent.ACTION_INSERT).apply {
    type = ContactsContract.Contacts.CONTENT_TYPE
}.also { intent ->
    // Make sure that the user has a contacts app installed on their device.
    intent.resolveActivity(packageManager)?.run {
        startActivity(intent)
    }
}

জাভা

// Delegates the responsibility of creating the contact to a contacts app,
// which has already been granted the appropriate WRITE_CONTACTS permission.
Intent insertContactIntent = new Intent(Intent.ACTION_INSERT);
insertContactIntent.setType(ContactsContract.Contacts.CONTENT_TYPE);

// Make sure that the user has a contacts app installed on their device.
if (insertContactIntent.resolveActivity(getPackageManager()) != null) {
    startActivity(insertContactIntent);
}

উপরন্তু, যদি আপনার অ্যাপটিকে ফাইল-ভিত্তিক I/O- যেমন সঞ্চয়স্থান অ্যাক্সেস করা বা একটি ফাইল বেছে নেওয়ার প্রয়োজন হয়- তবে এটির বিশেষ অনুমতির প্রয়োজন নেই কারণ সিস্টেমটি আপনার অ্যাপের হয়ে কাজগুলি সম্পূর্ণ করতে পারে। আরও ভাল, কোনও ব্যবহারকারী একটি নির্দিষ্ট ইউআরআই-তে সামগ্রী নির্বাচন করার পরে, কলিং অ্যাপটি নির্বাচিত সংস্থানের অনুমতি পায়।

সম্পর্কিত তথ্য:

অ্যাপ জুড়ে নিরাপদে ডেটা শেয়ার করুন

আরও নিরাপদ পদ্ধতিতে অন্যান্য অ্যাপের সাথে আপনার অ্যাপের বিষয়বস্তু শেয়ার করতে এই সবথেকে ভাল অভ্যাসগুলি অনুসরণ করুন:

  • প্রয়োজন অনুযায়ী শুধুমাত্র-পঠন বা শুধুমাত্র লেখার অনুমতি প্রয়োগ করুন।
  • FLAG_GRANT_READ_URI_PERMISSION এবং FLAG_GRANT_WRITE_URI_PERMISSION ফ্ল্যাগগুলি ব্যবহার করে ক্লায়েন্টদের ডেটাতে এককালীন অ্যাক্সেস প্রদান করুন৷
  • ডেটা শেয়ার করার সময়, content:// URIs ব্যবহার করুন, file:// URIs নয়। FileProvider এর উদাহরণগুলি আপনার জন্য এটি করে।

নিচের কোড স্নিপেটটি দেখায় কিভাবে ইউআরআই অনুমতি মঞ্জুর ফ্ল্যাগ ব্যবহার করতে হয় এবং একটি পৃথক পিডিএফ ভিউয়ার অ্যাপে একটি অ্যাপের পিডিএফ ফাইল প্রদর্শন করতে সামগ্রী প্রদানকারীর অনুমতি দেয়:

কোটলিন

// Create an Intent to launch a PDF viewer for a file owned by this app.
Intent(Intent.ACTION_VIEW).apply {
    data = Uri.parse("content://com.example/personal-info.pdf")

    // This flag gives the started app read access to the file.
    addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}.also { intent ->
    // Make sure that the user has a PDF viewer app installed on their device.
    intent.resolveActivity(packageManager)?.run {
        startActivity(intent)
    }
}

জাভা

// Create an Intent to launch a PDF viewer for a file owned by this app.
Intent viewPdfIntent = new Intent(Intent.ACTION_VIEW);
viewPdfIntent.setData(Uri.parse("content://com.example/personal-info.pdf"));

// This flag gives the started app read access to the file.
viewPdfIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

// Make sure that the user has a PDF viewer app installed on their device.
if (viewPdfIntent.resolveActivity(getPackageManager()) != null) {
    startActivity(viewPdfIntent);
}

দ্রষ্টব্য: লিখনযোগ্য অ্যাপ হোম ডিরেক্টরি থেকে ফাইলগুলি সম্পাদন করা একটি W^X লঙ্ঘন । এই কারণে, অবিশ্বস্ত অ্যাপগুলি যেগুলি Android 10 (API স্তর 29) এবং উচ্চতরকে লক্ষ্য করে তারা অ্যাপের হোম ডিরেক্টরির মধ্যে ফাইলগুলিতে exec() চালু করতে পারে না, শুধুমাত্র একটি অ্যাপের APK ফাইলের মধ্যে এমবেড করা বাইনারি কোড। এছাড়াও, যে অ্যাপগুলি Android 10 এবং উচ্চতরকে লক্ষ্য করে, সেগুলি মেমরিতে, dlopen() দিয়ে খোলা ফাইলগুলি থেকে এক্সিকিউটেবল কোড পরিবর্তন করতে পারে না৷ এতে টেক্সট রিলোকেশন সহ যেকোনও শেয়ার করা অবজেক্ট ( .so ) ফাইল অন্তর্ভুক্ত থাকে।

সম্পর্কিত তথ্য: android:grantUriPermissions

নিরাপদে ডেটা সংরক্ষণ করুন

যদিও আপনার অ্যাপের সংবেদনশীল ব্যবহারকারীর তথ্যে অ্যাক্সেসের প্রয়োজন হতে পারে, ব্যবহারকারীরা আপনার অ্যাপকে শুধুমাত্র তাদের ডেটাতে অ্যাক্সেস দেয় যদি তারা বিশ্বাস করে যে আপনি এটি সঠিকভাবে সুরক্ষিত রেখেছেন।

অভ্যন্তরীণ স্টোরেজের মধ্যে ব্যক্তিগত তথ্য সংরক্ষণ করুন

ডিভাইসের অভ্যন্তরীণ স্টোরেজের মধ্যে সমস্ত ব্যক্তিগত ব্যবহারকারীর ডেটা সঞ্চয় করুন, যা প্রতি অ্যাপে স্যান্ডবক্স করা হয়। আপনার অ্যাপকে এই ফাইলগুলি দেখার অনুমতির অনুরোধ করার প্রয়োজন নেই এবং অন্যান্য অ্যাপগুলি ফাইলগুলি অ্যাক্সেস করতে পারে না৷ একটি অতিরিক্ত নিরাপত্তা ব্যবস্থা হিসাবে, ব্যবহারকারী যখন একটি অ্যাপ আনইনস্টল করেন, তখন ডিভাইসটি অভ্যন্তরীণ স্টোরেজের মধ্যে অ্যাপটি সংরক্ষিত সমস্ত ফাইল মুছে দেয়।

নিম্নলিখিত কোড স্নিপেট অভ্যন্তরীণ সঞ্চয়স্থানে ডেটা লেখার একটি উপায় প্রদর্শন করে:

কোটলিন

// Creates a file with this name, or replaces an existing file
// that has the same name. Note that the file name cannot contain
// path separators.
val FILE_NAME = "sensitive_info.txt"
val fileContents = "This is some top-secret information!"
File(filesDir, FILE_NAME).bufferedWriter().use { writer ->
    writer.write(fileContents)
}

জাভা

// Creates a file with this name, or replaces an existing file
// that has the same name. Note that the file name cannot contain
// path separators.
final String FILE_NAME = "sensitive_info.txt";
String fileContents = "This is some top-secret information!";
try (BufferedWriter writer =
             new BufferedWriter(new FileWriter(new File(getFilesDir(), FILE_NAME)))) {
    writer.write(fileContents);
} catch (IOException e) {
    // Handle exception.
}

নিম্নলিখিত কোড স্নিপেট অভ্যন্তরীণ সঞ্চয়স্থান থেকে ডেটা পড়া, বিপরীত অপারেশন দেখায়:

কোটলিন

val FILE_NAME = "sensitive_info.txt"
val contents = File(filesDir, FILE_NAME).bufferedReader().useLines { lines ->
    lines.fold("") { working, line ->
        "$working\n$line"
    }
}

জাভা

final String FILE_NAME = "sensitive_info.txt";
StringBuffer stringBuffer = new StringBuffer();
try (BufferedReader reader =
             new BufferedReader(new FileReader(new File(getFilesDir(), FILE_NAME)))) {

    String line = reader.readLine();
    while (line != null) {
        stringBuffer.append(line).append('\n');
        line = reader.readLine();
    }
} catch (IOException e) {
    // Handle exception.
}

সম্পর্কিত তথ্য:

ব্যবহারের ক্ষেত্রের উপর ভিত্তি করে বাহ্যিক সঞ্চয়স্থানে ডেটা সংরক্ষণ করুন

বড়, অ-সংবেদনশীল ফাইলগুলির জন্য বাহ্যিক সঞ্চয়স্থান ব্যবহার করুন যা আপনার অ্যাপের জন্য নির্দিষ্ট এবং সেইসাথে আপনার অ্যাপ অন্যান্য অ্যাপের সাথে শেয়ার করা ফাইলগুলির জন্য। আপনি যে নির্দিষ্ট APIগুলি ব্যবহার করেন তা নির্ভর করে আপনার অ্যাপটি অ্যাপ-নির্দিষ্ট ফাইলগুলি অ্যাক্সেস করতে বা শেয়ার করা ফাইলগুলি অ্যাক্সেস করার জন্য ডিজাইন করা হয়েছে কিনা তার উপর।

যদি কোনো ফাইলে ব্যক্তিগত বা সংবেদনশীল তথ্য না থাকে কিন্তু শুধুমাত্র আপনার অ্যাপে ব্যবহারকারীকে মূল্য প্রদান করে, তাহলে ফাইলটিকে এক্সটার্নাল স্টোরেজে একটি অ্যাপ-নির্দিষ্ট ডিরেক্টরিতে সংরক্ষণ করুন।

যদি আপনার অ্যাপের এমন কোনো ফাইল অ্যাক্সেস বা স্টোর করার প্রয়োজন হয় যা অন্য অ্যাপের মান প্রদান করে, তাহলে আপনার ব্যবহারের ক্ষেত্রে নির্ভর করে নিম্নলিখিত APIগুলির মধ্যে একটি ব্যবহার করুন:

স্টোরেজ ভলিউমের প্রাপ্যতা পরীক্ষা করুন

যদি আপনার অ্যাপটি একটি অপসারণযোগ্য বাহ্যিক স্টোরেজ ডিভাইসের সাথে ইন্টারঅ্যাক্ট করে, তাহলে মনে রাখবেন যে ব্যবহারকারী স্টোরেজ ডিভাইসটি সরিয়ে ফেলতে পারে যখন আপনার অ্যাপটি অ্যাক্সেস করার চেষ্টা করছে। স্টোরেজ ডিভাইস উপলব্ধ কিনা তা যাচাই করতে যুক্তি অন্তর্ভুক্ত করুন।

ডেটার বৈধতা পরীক্ষা করুন

যদি আপনার অ্যাপটি বাহ্যিক স্টোরেজ থেকে ডেটা ব্যবহার করে, তবে নিশ্চিত করুন যে ডেটার বিষয়বস্তুগুলি দূষিত বা সংশোধন করা হয়নি। স্থিতিশীল বিন্যাসে আর নেই এমন ফাইলগুলি পরিচালনা করার জন্য যুক্তি অন্তর্ভুক্ত করুন।

নিম্নলিখিত কোড স্নিপেটে একটি হ্যাশ যাচাইকারীর উদাহরণ রয়েছে:

কোটলিন

val hash = calculateHash(stream)
// Store "expectedHash" in a secure location.
if (hash == expectedHash) {
    // Work with the content.
}

// Calculating the hash code can take quite a bit of time, so it shouldn't
// be done on the main thread.
suspend fun calculateHash(stream: InputStream): String {
    return withContext(Dispatchers.IO) {
        val digest = MessageDigest.getInstance("SHA-512")
        val digestStream = DigestInputStream(stream, digest)
        while (digestStream.read() != -1) {
            // The DigestInputStream does the work; nothing for us to do.
        }
        digest.digest().joinToString(":") { "%02x".format(it) }
    }
}

জাভা

Executor threadPoolExecutor = Executors.newFixedThreadPool(4);
private interface HashCallback {
    void onHashCalculated(@Nullable String hash);
}

boolean hashRunning = calculateHash(inputStream, threadPoolExecutor, hash -> {
    if (Objects.equals(hash, expectedHash)) {
        // Work with the content.
    }
});

if (!hashRunning) {
    // There was an error setting up the hash function.
}

private boolean calculateHash(@NonNull InputStream stream,
                              @NonNull Executor executor,
                              @NonNull HashCallback hashCallback) {
    final MessageDigest digest;
    try {
        digest = MessageDigest.getInstance("SHA-512");
    } catch (NoSuchAlgorithmException nsa) {
        return false;
    }

    // Calculating the hash code can take quite a bit of time, so it shouldn't
    // be done on the main thread.
    executor.execute(() -> {
        String hash;
        try (DigestInputStream digestStream =
                new DigestInputStream(stream, digest)) {
            while (digestStream.read() != -1) {
                // The DigestInputStream does the work; nothing for us to do.
            }
            StringBuilder builder = new StringBuilder();
            for (byte aByte : digest.digest()) {
                builder.append(String.format("%02x", aByte)).append(':');
            }
            hash = builder.substring(0, builder.length() - 1);
        } catch (IOException e) {
            hash = null;
        }

        final String calculatedHash = hash;
        runOnUiThread(() -> hashCallback.onHashCalculated(calculatedHash));
    });
    return true;
}

ক্যাশে ফাইলগুলিতে শুধুমাত্র অ-সংবেদনশীল ডেটা সংরক্ষণ করুন

অ-সংবেদনশীল অ্যাপ ডেটাতে দ্রুত অ্যাক্সেস প্রদান করতে, এটি ডিভাইসের ক্যাশে সংরক্ষণ করুন। 1 MB এর চেয়ে বড় ক্যাশেগুলির জন্য, getExternalCacheDir() ব্যবহার করুন। 1 MB বা ছোট ক্যাশেগুলির জন্য, getCacheDir() ব্যবহার করুন৷ উভয় পদ্ধতিই আপনাকে File অবজেক্ট প্রদান করে যাতে আপনার অ্যাপের ক্যাশে করা ডেটা থাকে।

নিম্নলিখিত কোড স্নিপেট দেখায় যে আপনার অ্যাপ সম্প্রতি ডাউনলোড করা একটি ফাইল কীভাবে ক্যাশে করবেন:

কোটলিন

val cacheFile = File(myDownloadedFileUri).let { fileToCache ->
    File(cacheDir.path, fileToCache.name)
}

জাভা

File cacheDir = getCacheDir();
File fileToCache = new File(myDownloadedFileUri);
String fileToCacheName = fileToCache.getName();
File cacheFile = new File(cacheDir.getPath(), fileToCacheName);

দ্রষ্টব্য: আপনি শেয়ার্ড স্টোরেজের মধ্যে আপনার অ্যাপের ক্যাশে রাখার জন্য getExternalCacheDir() ব্যবহার করলে, আপনার অ্যাপ চলাকালীন ব্যবহারকারী এই স্টোরেজ ধারণকারী মিডিয়া বের করে দিতে পারে। এই ব্যবহারকারীর আচরণের কারণে ক্যাশে মিসকে সুন্দরভাবে পরিচালনা করার জন্য যুক্তি অন্তর্ভুক্ত করুন।

সতর্কতা: এই ফাইলগুলিতে কোন নিরাপত্তা বলবৎ নেই। তাই, যেকোন অ্যাপ যেটি Android 10 (API লেভেল 29) বা তার নিচের দিকে লক্ষ্য করে এবং WRITE_EXTERNAL_STORAGE অনুমতি আছে তারা এই ক্যাশের বিষয়বস্তু অ্যাক্সেস করতে পারে।

সম্পর্কিত তথ্য: ডেটা এবং ফাইল স্টোরেজ ওভারভিউ

ব্যক্তিগত মোডে SharedPreferences ব্যবহার করুন

আপনার অ্যাপের SharedPreferences অবজেক্ট তৈরি বা অ্যাক্সেস করতে getSharedPreferences() ব্যবহার করার সময়, MODE_PRIVATE ব্যবহার করুন। এইভাবে, শুধুমাত্র আপনার অ্যাপ শেয়ার করা পছন্দ ফাইলের মধ্যে তথ্য অ্যাক্সেস করতে পারে।

আপনি যদি সমস্ত অ্যাপ জুড়ে ডেটা ভাগ করতে চান, তাহলে SharedPreferences অবজেক্ট ব্যবহার করবেন না। পরিবর্তে, অ্যাপ্লিকেশানগুলিতে নিরাপদে ডেটা ভাগ করতে পদক্ষেপগুলি অনুসরণ করুন৷

সিকিউরিটি লাইব্রেরি এনক্রিপ্টেড শেয়ারডপ্রেফারেন্স ক্লাসও প্রদান করে যা শেয়ারডপ্রেফারেন্স ক্লাসকে মোড়ানো হয় এবং কী এবং মানগুলি স্বয়ংক্রিয়ভাবে এনক্রিপ্ট করে।

সম্পর্কিত তথ্য:

পরিষেবা এবং নির্ভরতা আপ টু ডেট রাখুন

বেশিরভাগ অ্যাপ বিশেষায়িত কাজগুলি সম্পূর্ণ করতে বাহ্যিক লাইব্রেরি এবং ডিভাইস সিস্টেম তথ্য ব্যবহার করে। আপনার অ্যাপের নির্ভরতা আপ টু ডেট রেখে, আপনি যোগাযোগের এই পয়েন্টগুলিকে আরও সুরক্ষিত করে তোলেন৷

Google Play পরিষেবা নিরাপত্তা প্রদানকারী চেক করুন

দ্রষ্টব্য: এই বিভাগটি শুধুমাত্র এমন অ্যাপগুলির জন্য প্রযোজ্য যেগুলিকে লক্ষ্য করে এমন ডিভাইসগুলিতে Google Play পরিষেবাগুলি ইনস্টল করা আছে৷

যদি আপনার অ্যাপটি Google Play পরিষেবা ব্যবহার করে, তাহলে নিশ্চিত করুন যে আপনার অ্যাপটি ইনস্টল করা ডিভাইসে এটি আপডেট করা আছে। UI থ্রেডের বাইরে, অ্যাসিঙ্ক্রোনাসভাবে চেকটি সম্পাদন করুন। ডিভাইসটি আপ টু ডেট না হলে, একটি অনুমোদন ত্রুটি ট্রিগার করুন।

আপনার অ্যাপটি যে ডিভাইসে ইনস্টল করা আছে সেখানে Google Play পরিষেবাগুলি আপ টু ডেট আছে কিনা তা নির্ধারণ করতে, SSL শোষণের বিরুদ্ধে সুরক্ষার জন্য আপনার নিরাপত্তা প্রদানকারীকে আপডেট করার বিষয়ে নির্দেশিত পদক্ষেপগুলি অনুসরণ করুন৷

সম্পর্কিত তথ্য:

সমস্ত অ্যাপ নির্ভরতা আপডেট করুন

আপনার অ্যাপ স্থাপন করার আগে, নিশ্চিত করুন যে সমস্ত লাইব্রেরি, SDK এবং অন্যান্য নির্ভরতা আপ টু ডেট আছে:

  • Android SDK-এর মতো প্রথম-পক্ষ নির্ভরতার জন্য, Android স্টুডিওতে পাওয়া আপডেট করার সরঞ্জামগুলি ব্যবহার করুন, যেমন SDK ম্যানেজার
  • তৃতীয় পক্ষের নির্ভরতাগুলির জন্য, আপনার অ্যাপ ব্যবহার করে এমন লাইব্রেরিগুলির ওয়েবসাইটগুলি পরীক্ষা করুন এবং উপলব্ধ আপডেট এবং নিরাপত্তা প্যাচগুলি ইনস্টল করুন৷

সম্পর্কিত তথ্য: বিল্ড নির্ভরতা যোগ করুন

আরও তথ্য

কীভাবে আপনার অ্যাপকে আরও সুরক্ষিত করা যায় সে সম্পর্কে আরও জানতে, নিম্নলিখিত সংস্থানগুলি দেখুন:

,

আপনার অ্যাপকে আরও সুরক্ষিত করে আপনি ব্যবহারকারীর বিশ্বাস এবং ডিভাইসের অখণ্ডতা রক্ষা করতে সাহায্য করেন।

এই পৃষ্ঠাটি বেশ কয়েকটি সর্বোত্তম অনুশীলন উপস্থাপন করে যা আপনার অ্যাপের নিরাপত্তার উপর একটি উল্লেখযোগ্য, ইতিবাচক প্রভাব ফেলে।

নিরাপদ যোগাযোগ প্রয়োগ করুন

যখন আপনি আপনার অ্যাপ এবং অন্যান্য অ্যাপের মধ্যে বা আপনার অ্যাপ এবং কোনও ওয়েবসাইটের মধ্যে বিনিময় করা ডেটাকে সুরক্ষিত করেন, তখন আপনি আপনার অ্যাপের স্থায়িত্বকে উন্নত করেন এবং আপনার পাঠানো ও গ্রহণ করা ডেটাকে সুরক্ষিত করেন।

অ্যাপের মধ্যে যোগাযোগ রক্ষা করুন

আরও নিরাপদে অ্যাপগুলির মধ্যে যোগাযোগ করতে, একটি অ্যাপ চয়নকারী, স্বাক্ষর-ভিত্তিক অনুমতি এবং অ-রপ্তানিকৃত সামগ্রী প্রদানকারীদের সাথে অন্তর্নিহিত উদ্দেশ্যগুলি ব্যবহার করুন৷

একটি অ্যাপ চয়নকারী দেখান৷

যদি একটি অন্তর্নিহিত উদ্দেশ্য ব্যবহারকারীর ডিভাইসে কমপক্ষে দুটি সম্ভাব্য অ্যাপ চালু করতে পারে, তাহলে স্পষ্টভাবে একটি অ্যাপ চয়নকারী দেখান। এই মিথস্ক্রিয়া কৌশলটি ব্যবহারকারীদের তাদের বিশ্বাসযোগ্য একটি অ্যাপে সংবেদনশীল তথ্য স্থানান্তর করতে দেয়।

কোটলিন

val intent = Intent(Intent.ACTION_SEND)
val possibleActivitiesList: List<ResolveInfo> =
        packageManager.queryIntentActivities(intent, PackageManager.MATCH_ALL)

// Verify that an activity in at least two apps on the user's device
// can handle the intent. Otherwise, start the intent only if an app
// on the user's device can handle the intent.
if (possibleActivitiesList.size > 1) {

    // Create intent to show chooser.
    // Title is something similar to "Share this photo with."

    val chooser = resources.getString(R.string.chooser_title).let { title ->
        Intent.createChooser(intent, title)
    }
    startActivity(chooser)
} else if (intent.resolveActivity(packageManager) != null) {
    startActivity(intent)
}

জাভা

Intent intent = new Intent(Intent.ACTION_SEND);
List<ResolveInfo> possibleActivitiesList = getPackageManager()
        .queryIntentActivities(intent, PackageManager.MATCH_ALL);

// Verify that an activity in at least two apps on the user's device
// can handle the intent. Otherwise, start the intent only if an app
// on the user's device can handle the intent.
if (possibleActivitiesList.size() > 1) {

    // Create intent to show chooser.
    // Title is something similar to "Share this photo with."

    String title = getResources().getString(R.string.chooser_title);
    Intent chooser = Intent.createChooser(intent, title);
    startActivity(chooser);
} else if (intent.resolveActivity(getPackageManager()) != null) {
    startActivity(intent);
}

সম্পর্কিত তথ্য:

স্বাক্ষর-ভিত্তিক অনুমতি প্রয়োগ করুন

আপনার নিয়ন্ত্রণ বা মালিকানাধীন দুটি অ্যাপের মধ্যে ডেটা ভাগ করার সময়, স্বাক্ষর-ভিত্তিক অনুমতিগুলি ব্যবহার করুন৷ এই অনুমতিগুলির জন্য ব্যবহারকারীর নিশ্চিতকরণের প্রয়োজন হয় না এবং পরিবর্তে পরীক্ষা করে দেখুন যে ডেটা অ্যাক্সেস করা অ্যাপগুলি একই সাইনিং কী ব্যবহার করে সাইন করা হয়েছে। অতএব, এই অনুমতিগুলি আরও সুগমিত, নিরাপদ ব্যবহারকারীর অভিজ্ঞতা প্রদান করে।

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapp">
    <permission android:name="my_custom_permission_name"
                android:protectionLevel="signature" />

সম্পর্কিত তথ্য:

আপনার অ্যাপের বিষয়বস্তু প্রদানকারীদের অ্যাক্সেসের অনুমতি দিন

যদি না আপনি আপনার অ্যাপ থেকে ডেটা পাঠাতে চান এমন একটি ভিন্ন অ্যাপে যা আপনার নিজের নয়, স্পষ্টভাবে অন্য ডেভেলপারদের অ্যাপগুলিকে আপনার অ্যাপের ContentProvider অবজেক্ট অ্যাক্সেস করা থেকে বিরত রাখুন। এই সেটিংটি বিশেষভাবে গুরুত্বপূর্ণ যদি আপনার অ্যাপটি Android 4.1.1 (API লেভেল 16) বা তার কম সংস্করণে চলমান ডিভাইসগুলিতে ইনস্টল করা যায়, কারণ <provider> উপাদানটির android:exported বৈশিষ্ট্যটি Android-এর সেই সংস্করণগুলিতে ডিফল্টরূপে true

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapp">
    <application ... >
        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="com.example.myapp.fileprovider"
            ...
            android:exported="false">
            <!-- Place child elements of <provider> here. -->
        </provider>
        ...
    </application>
</manifest>

সংবেদনশীল তথ্য দেখানোর আগে শংসাপত্রের জন্য জিজ্ঞাসা করুন

ব্যবহারকারীদের কাছ থেকে শংসাপত্রের অনুরোধ করার সময় যাতে তারা আপনার অ্যাপে সংবেদনশীল তথ্য বা প্রিমিয়াম সামগ্রী অ্যাক্সেস করতে পারে, একটি পিন/পাসওয়ার্ড/প্যাটার্ন বা বায়োমেট্রিক শংসাপত্রের জন্য জিজ্ঞাসা করুন, যেমন মুখ শনাক্তকরণ বা আঙুলের ছাপ শনাক্তকরণ৷

কীভাবে বায়োমেট্রিক শংসাপত্রের অনুরোধ করতে হয় সে সম্পর্কে আরও জানতে, বায়োমেট্রিক প্রমাণীকরণ সম্পর্কে নির্দেশিকাটি দেখুন।

নেটওয়ার্ক নিরাপত্তা ব্যবস্থা প্রয়োগ করুন

নিম্নলিখিত বিভাগগুলি বর্ণনা করে যে আপনি কীভাবে আপনার অ্যাপের নেটওয়ার্ক নিরাপত্তা উন্নত করতে পারেন৷

TLS ট্রাফিক ব্যবহার করুন

যদি আপনার অ্যাপটি এমন একটি ওয়েব সার্ভারের সাথে যোগাযোগ করে যার একটি সুপরিচিত, বিশ্বস্ত সার্টিফিকেট অথরিটি (CA) দ্বারা জারি করা শংসাপত্র রয়েছে, তাহলে নিম্নোক্ত মত একটি HTTPS অনুরোধ ব্যবহার করুন:

কোটলিন

val url = URL("https://www.google.com")
val urlConnection = url.openConnection() as HttpsURLConnection
urlConnection.connect()
urlConnection.inputStream.use {
    ...
}

জাভা

URL url = new URL("https://www.google.com");
HttpsURLConnection urlConnection = (HttpsURLConnection) url.openConnection();
urlConnection.connect();
InputStream in = urlConnection.getInputStream();

একটি নেটওয়ার্ক নিরাপত্তা কনফিগারেশন যোগ করুন

যদি আপনার অ্যাপ নতুন বা কাস্টম CA ব্যবহার করে, তাহলে আপনি একটি কনফিগারেশন ফাইলে আপনার নেটওয়ার্কের নিরাপত্তা সেটিংস ঘোষণা করতে পারেন। এই প্রক্রিয়াটি আপনাকে কোনো অ্যাপ কোড পরিবর্তন না করেই কনফিগারেশন তৈরি করতে দেয়।

আপনার অ্যাপে একটি নেটওয়ার্ক নিরাপত্তা কনফিগারেশন ফাইল যোগ করতে, এই পদক্ষেপগুলি অনুসরণ করুন:

  1. আপনার অ্যাপের ম্যানিফেস্টে কনফিগারেশন ঘোষণা করুন:
  2. <manifest ... >
        <application
            android:networkSecurityConfig="@xml/network_security_config"
            ... >
            <!-- Place child elements of <application> element here. -->
        </application>
    </manifest>
  3. res/xml/network_security_config.xml এ অবস্থিত একটি XML রিসোর্স ফাইল যোগ করুন।

    নির্দিষ্ট করুন যে নির্দিষ্ট ডোমেনে সমস্ত ট্র্যাফিক অবশ্যই ক্লিয়ার-টেক্সট অক্ষম করে HTTPS ব্যবহার করবে:

    <network-security-config>
        <domain-config cleartextTrafficPermitted="false">
            <domain includeSubdomains="true">secure.example.com</domain>
            ...
        </domain-config>
    </network-security-config>

    বিকাশ প্রক্রিয়া চলাকালীন, আপনি ব্যবহারকারী-ইনস্টল করা শংসাপত্রগুলিকে স্পষ্টভাবে অনুমতি দিতে <debug-overrides> উপাদান ব্যবহার করতে পারেন। এই উপাদানটি অ্যাপের রিলিজ কনফিগারেশনকে প্রভাবিত না করেই ডিবাগিং এবং পরীক্ষার সময় আপনার অ্যাপের নিরাপত্তা-সমালোচনামূলক বিকল্পগুলিকে ওভাররাইড করে। নিম্নলিখিত স্নিপেটটি আপনার অ্যাপের নেটওয়ার্ক নিরাপত্তা কনফিগারেশন XML ফাইলে এই উপাদানটিকে কীভাবে সংজ্ঞায়িত করতে হয় তা দেখায়:

    <network-security-config>
        <debug-overrides>
            <trust-anchors>
                <certificates src="user" />
            </trust-anchors>
        </debug-overrides>
    </network-security-config>

সম্পর্কিত তথ্য: নেটওয়ার্ক নিরাপত্তা কনফিগারেশন

আপনার নিজের ট্রাস্ট ম্যানেজার তৈরি করুন

আপনার TLS পরীক্ষকের প্রতিটি শংসাপত্র গ্রহণ করা উচিত নয়। নিম্নলিখিত শর্তগুলির মধ্যে একটি আপনার ব্যবহারের ক্ষেত্রে প্রযোজ্য হলে আপনাকে একটি ট্রাস্ট ম্যানেজার সেট আপ করতে এবং সমস্ত TLS সতর্কতাগুলি পরিচালনা করতে হতে পারে:

  • আপনি একটি ওয়েব সার্ভারের সাথে যোগাযোগ করছেন যাতে একটি নতুন বা কাস্টম CA দ্বারা স্বাক্ষরিত একটি শংসাপত্র রয়েছে৷
  • আপনি যে ডিভাইসটি ব্যবহার করছেন তার দ্বারা সেই CA বিশ্বাসযোগ্য নয়৷
  • আপনি একটি নেটওয়ার্ক নিরাপত্তা কনফিগারেশন ব্যবহার করতে পারবেন না৷

এই পদক্ষেপগুলি কীভাবে সম্পূর্ণ করবেন সে সম্পর্কে আরও জানতে, একটি অজানা শংসাপত্র কর্তৃপক্ষ পরিচালনার বিষয়ে আলোচনাটি দেখুন।

সম্পর্কিত তথ্য:

WebView অবজেক্ট সাবধানে ব্যবহার করুন

আপনার অ্যাপের WebView অবজেক্টগুলি ব্যবহারকারীদের এমন সাইটগুলিতে নেভিগেট করতে দেয় না যা আপনার নিয়ন্ত্রণের বাইরে। যখনই সম্ভব, আপনার অ্যাপের WebView অবজেক্ট দ্বারা লোড করা সামগ্রীকে সীমাবদ্ধ করতে অনুমতি তালিকা ব্যবহার করুন।

উপরন্তু, জাভাস্ক্রিপ্ট ইন্টারফেস সমর্থন সক্ষম করবেন না যদি না আপনি সম্পূর্ণরূপে আপনার অ্যাপের WebView অবজেক্টের বিষয়বস্তু নিয়ন্ত্রণ এবং বিশ্বাস করেন।

HTML বার্তা চ্যানেল ব্যবহার করুন

যদি আপনার অ্যাপ অবশ্যই Android 6.0 (API লেভেল 23) এবং তার উপরে চলমান ডিভাইসগুলিতে JavaScript ইন্টারফেস সমর্থন ব্যবহার করে, তাহলে নিম্নলিখিত কোড স্নিপেটে দেখানো হিসাবে ওয়েবসাইট এবং আপনার অ্যাপের মধ্যে যোগাযোগের পরিবর্তে HTML বার্তা চ্যানেলগুলি ব্যবহার করুন:

কোটলিন

val myWebView: WebView = findViewById(R.id.webview)

// channel[0] and channel[1] represent the two ports.
// They are already entangled with each other and have been started.
val channel: Array<out WebMessagePort> = myWebView.createWebMessageChannel()

// Create handler for channel[0] to receive messages.
channel[0].setWebMessageCallback(object : WebMessagePort.WebMessageCallback() {

    override fun onMessage(port: WebMessagePort, message: WebMessage) {
        Log.d(TAG, "On port $port, received this message: $message")
    }
})

// Send a message from channel[1] to channel[0].
channel[1].postMessage(WebMessage("My secure message"))

জাভা

WebView myWebView = (WebView) findViewById(R.id.webview);

// channel[0] and channel[1] represent the two ports.
// They are already entangled with each other and have been started.
WebMessagePort[] channel = myWebView.createWebMessageChannel();

// Create handler for channel[0] to receive messages.
channel[0].setWebMessageCallback(new WebMessagePort.WebMessageCallback() {
    @Override
    public void onMessage(WebMessagePort port, WebMessage message) {
         Log.d(TAG, "On port " + port + ", received this message: " + message);
    }
});

// Send a message from channel[1] to channel[0].
channel[1].postMessage(new WebMessage("My secure message"));

সম্পর্কিত তথ্য:

সঠিক অনুমতি প্রদান করুন

আপনার অ্যাপটি সঠিকভাবে কাজ করার জন্য প্রয়োজনীয় ন্যূনতম সংখ্যক অনুমতির অনুরোধ করুন। যখন সম্ভব, আপনার অ্যাপের আর প্রয়োজন না হলে অনুমতি ত্যাগ করুন।

অনুমতি স্থগিত করতে উদ্দেশ্য ব্যবহার করুন

যখনই সম্ভব, অন্য অ্যাপে সম্পন্ন করা যেতে পারে এমন একটি অ্যাকশন সম্পূর্ণ করার জন্য আপনার অ্যাপে অনুমতি যোগ করবেন না। পরিবর্তে, ইতিমধ্যেই প্রয়োজনীয় অনুমতি রয়েছে এমন একটি ভিন্ন অ্যাপে অনুরোধটি পিছিয়ে দেওয়ার জন্য একটি উদ্দেশ্য ব্যবহার করুন।

নিম্নলিখিত উদাহরণটি দেখায় যে কীভাবে ব্যবহারকারীদের READ_CONTACTS এবং WRITE_CONTACTS অনুমতির অনুরোধ করার পরিবর্তে একটি পরিচিতি অ্যাপে নির্দেশিত করতে একটি অভিপ্রায় ব্যবহার করতে হয়:

কোটলিন

// Delegates the responsibility of creating the contact to a contacts app,
// which has already been granted the appropriate WRITE_CONTACTS permission.
Intent(Intent.ACTION_INSERT).apply {
    type = ContactsContract.Contacts.CONTENT_TYPE
}.also { intent ->
    // Make sure that the user has a contacts app installed on their device.
    intent.resolveActivity(packageManager)?.run {
        startActivity(intent)
    }
}

জাভা

// Delegates the responsibility of creating the contact to a contacts app,
// which has already been granted the appropriate WRITE_CONTACTS permission.
Intent insertContactIntent = new Intent(Intent.ACTION_INSERT);
insertContactIntent.setType(ContactsContract.Contacts.CONTENT_TYPE);

// Make sure that the user has a contacts app installed on their device.
if (insertContactIntent.resolveActivity(getPackageManager()) != null) {
    startActivity(insertContactIntent);
}

উপরন্তু, যদি আপনার অ্যাপটিকে ফাইল-ভিত্তিক I/O- যেমন সঞ্চয়স্থান অ্যাক্সেস করা বা একটি ফাইল বেছে নেওয়ার প্রয়োজন হয়- তবে এটির বিশেষ অনুমতির প্রয়োজন নেই কারণ সিস্টেমটি আপনার অ্যাপের হয়ে কাজগুলি সম্পূর্ণ করতে পারে। আরও ভাল, কোনও ব্যবহারকারী একটি নির্দিষ্ট ইউআরআই-তে সামগ্রী নির্বাচন করার পরে, কলিং অ্যাপটি নির্বাচিত সংস্থানের অনুমতি পায়।

সম্পর্কিত তথ্য:

অ্যাপ জুড়ে নিরাপদে ডেটা শেয়ার করুন

আরও নিরাপদ পদ্ধতিতে অন্যান্য অ্যাপের সাথে আপনার অ্যাপের বিষয়বস্তু শেয়ার করতে এই সবথেকে ভাল অভ্যাসগুলি অনুসরণ করুন:

  • প্রয়োজন অনুযায়ী শুধুমাত্র-পঠন বা শুধুমাত্র লেখার অনুমতি প্রয়োগ করুন।
  • FLAG_GRANT_READ_URI_PERMISSION এবং FLAG_GRANT_WRITE_URI_PERMISSION ফ্ল্যাগগুলি ব্যবহার করে ক্লায়েন্টদের ডেটাতে এককালীন অ্যাক্সেস প্রদান করুন৷
  • ডেটা শেয়ার করার সময়, content:// URIs ব্যবহার করুন, file:// URIs নয়। FileProvider এর উদাহরণগুলি আপনার জন্য এটি করে।

নিচের কোড স্নিপেটটি দেখায় কিভাবে ইউআরআই অনুমতি মঞ্জুর ফ্ল্যাগ ব্যবহার করতে হয় এবং একটি পৃথক পিডিএফ ভিউয়ার অ্যাপে একটি অ্যাপের পিডিএফ ফাইল প্রদর্শন করতে সামগ্রী প্রদানকারীর অনুমতি দেয়:

কোটলিন

// Create an Intent to launch a PDF viewer for a file owned by this app.
Intent(Intent.ACTION_VIEW).apply {
    data = Uri.parse("content://com.example/personal-info.pdf")

    // This flag gives the started app read access to the file.
    addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
}.also { intent ->
    // Make sure that the user has a PDF viewer app installed on their device.
    intent.resolveActivity(packageManager)?.run {
        startActivity(intent)
    }
}

জাভা

// Create an Intent to launch a PDF viewer for a file owned by this app.
Intent viewPdfIntent = new Intent(Intent.ACTION_VIEW);
viewPdfIntent.setData(Uri.parse("content://com.example/personal-info.pdf"));

// This flag gives the started app read access to the file.
viewPdfIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

// Make sure that the user has a PDF viewer app installed on their device.
if (viewPdfIntent.resolveActivity(getPackageManager()) != null) {
    startActivity(viewPdfIntent);
}

দ্রষ্টব্য: লিখনযোগ্য অ্যাপ হোম ডিরেক্টরি থেকে ফাইলগুলি সম্পাদন করা একটি W^X লঙ্ঘন । এই কারণে, অবিশ্বস্ত অ্যাপগুলি যেগুলি Android 10 (API স্তর 29) এবং উচ্চতরকে লক্ষ্য করে তারা অ্যাপের হোম ডিরেক্টরির মধ্যে ফাইলগুলিতে exec() চালু করতে পারে না, শুধুমাত্র একটি অ্যাপের APK ফাইলের মধ্যে এমবেড করা বাইনারি কোড। এছাড়াও, যে অ্যাপগুলি Android 10 এবং উচ্চতরকে লক্ষ্য করে, সেগুলি মেমরিতে, dlopen() দিয়ে খোলা ফাইলগুলি থেকে এক্সিকিউটেবল কোড পরিবর্তন করতে পারে না৷ এতে টেক্সট রিলোকেশন সহ যেকোনও শেয়ার করা অবজেক্ট ( .so ) ফাইল অন্তর্ভুক্ত থাকে।

সম্পর্কিত তথ্য: android:grantUriPermissions

নিরাপদে ডেটা সংরক্ষণ করুন

যদিও আপনার অ্যাপের সংবেদনশীল ব্যবহারকারীর তথ্যে অ্যাক্সেসের প্রয়োজন হতে পারে, ব্যবহারকারীরা আপনার অ্যাপকে শুধুমাত্র তাদের ডেটাতে অ্যাক্সেস দেয় যদি তারা বিশ্বাস করে যে আপনি এটি সঠিকভাবে সুরক্ষিত রেখেছেন।

অভ্যন্তরীণ স্টোরেজের মধ্যে ব্যক্তিগত তথ্য সংরক্ষণ করুন

ডিভাইসের অভ্যন্তরীণ স্টোরেজের মধ্যে সমস্ত ব্যক্তিগত ব্যবহারকারীর ডেটা সঞ্চয় করুন, যা প্রতি অ্যাপে স্যান্ডবক্স করা হয়। আপনার অ্যাপকে এই ফাইলগুলি দেখার অনুমতির অনুরোধ করার প্রয়োজন নেই এবং অন্যান্য অ্যাপগুলি ফাইলগুলি অ্যাক্সেস করতে পারে না৷ একটি অতিরিক্ত নিরাপত্তা ব্যবস্থা হিসাবে, ব্যবহারকারী যখন একটি অ্যাপ আনইনস্টল করেন, তখন ডিভাইসটি অভ্যন্তরীণ স্টোরেজের মধ্যে অ্যাপটি সংরক্ষিত সমস্ত ফাইল মুছে দেয়।

নিম্নলিখিত কোড স্নিপেট অভ্যন্তরীণ সঞ্চয়স্থানে ডেটা লেখার একটি উপায় প্রদর্শন করে:

কোটলিন

// Creates a file with this name, or replaces an existing file
// that has the same name. Note that the file name cannot contain
// path separators.
val FILE_NAME = "sensitive_info.txt"
val fileContents = "This is some top-secret information!"
File(filesDir, FILE_NAME).bufferedWriter().use { writer ->
    writer.write(fileContents)
}

জাভা

// Creates a file with this name, or replaces an existing file
// that has the same name. Note that the file name cannot contain
// path separators.
final String FILE_NAME = "sensitive_info.txt";
String fileContents = "This is some top-secret information!";
try (BufferedWriter writer =
             new BufferedWriter(new FileWriter(new File(getFilesDir(), FILE_NAME)))) {
    writer.write(fileContents);
} catch (IOException e) {
    // Handle exception.
}

নিম্নলিখিত কোড স্নিপেট অভ্যন্তরীণ সঞ্চয়স্থান থেকে ডেটা পড়া, বিপরীত অপারেশন দেখায়:

কোটলিন

val FILE_NAME = "sensitive_info.txt"
val contents = File(filesDir, FILE_NAME).bufferedReader().useLines { lines ->
    lines.fold("") { working, line ->
        "$working\n$line"
    }
}

জাভা

final String FILE_NAME = "sensitive_info.txt";
StringBuffer stringBuffer = new StringBuffer();
try (BufferedReader reader =
             new BufferedReader(new FileReader(new File(getFilesDir(), FILE_NAME)))) {

    String line = reader.readLine();
    while (line != null) {
        stringBuffer.append(line).append('\n');
        line = reader.readLine();
    }
} catch (IOException e) {
    // Handle exception.
}

সম্পর্কিত তথ্য:

ব্যবহারের ক্ষেত্রের উপর ভিত্তি করে বাহ্যিক সঞ্চয়স্থানে ডেটা সংরক্ষণ করুন

বড়, অ-সংবেদনশীল ফাইলগুলির জন্য বাহ্যিক সঞ্চয়স্থান ব্যবহার করুন যা আপনার অ্যাপের জন্য নির্দিষ্ট এবং সেইসাথে আপনার অ্যাপ অন্যান্য অ্যাপের সাথে শেয়ার করা ফাইলগুলির জন্য। আপনি যে নির্দিষ্ট APIগুলি ব্যবহার করেন তা নির্ভর করে আপনার অ্যাপটি অ্যাপ-নির্দিষ্ট ফাইলগুলি অ্যাক্সেস করতে বা শেয়ার করা ফাইলগুলি অ্যাক্সেস করার জন্য ডিজাইন করা হয়েছে কিনা তার উপর।

যদি কোনো ফাইলে ব্যক্তিগত বা সংবেদনশীল তথ্য না থাকে কিন্তু শুধুমাত্র আপনার অ্যাপে ব্যবহারকারীকে মূল্য প্রদান করে, তাহলে ফাইলটিকে এক্সটার্নাল স্টোরেজে একটি অ্যাপ-নির্দিষ্ট ডিরেক্টরিতে সংরক্ষণ করুন।

যদি আপনার অ্যাপের এমন কোনো ফাইল অ্যাক্সেস বা স্টোর করার প্রয়োজন হয় যা অন্য অ্যাপের মান প্রদান করে, তাহলে আপনার ব্যবহারের ক্ষেত্রে নির্ভর করে নিম্নলিখিত APIগুলির মধ্যে একটি ব্যবহার করুন:

স্টোরেজ ভলিউমের প্রাপ্যতা পরীক্ষা করুন

যদি আপনার অ্যাপটি একটি অপসারণযোগ্য বাহ্যিক স্টোরেজ ডিভাইসের সাথে ইন্টারঅ্যাক্ট করে, তাহলে মনে রাখবেন যে ব্যবহারকারী স্টোরেজ ডিভাইসটি সরিয়ে ফেলতে পারে যখন আপনার অ্যাপটি অ্যাক্সেস করার চেষ্টা করছে। স্টোরেজ ডিভাইস উপলব্ধ কিনা তা যাচাই করতে যুক্তি অন্তর্ভুক্ত করুন।

ডেটার বৈধতা পরীক্ষা করুন

যদি আপনার অ্যাপটি বাহ্যিক স্টোরেজ থেকে ডেটা ব্যবহার করে, তবে নিশ্চিত করুন যে ডেটার বিষয়বস্তুগুলি দূষিত বা সংশোধন করা হয়নি। স্থিতিশীল বিন্যাসে আর নেই এমন ফাইলগুলি পরিচালনা করার জন্য যুক্তি অন্তর্ভুক্ত করুন।

নিম্নলিখিত কোড স্নিপেটে একটি হ্যাশ যাচাইকারীর উদাহরণ রয়েছে:

কোটলিন

val hash = calculateHash(stream)
// Store "expectedHash" in a secure location.
if (hash == expectedHash) {
    // Work with the content.
}

// Calculating the hash code can take quite a bit of time, so it shouldn't
// be done on the main thread.
suspend fun calculateHash(stream: InputStream): String {
    return withContext(Dispatchers.IO) {
        val digest = MessageDigest.getInstance("SHA-512")
        val digestStream = DigestInputStream(stream, digest)
        while (digestStream.read() != -1) {
            // The DigestInputStream does the work; nothing for us to do.
        }
        digest.digest().joinToString(":") { "%02x".format(it) }
    }
}

জাভা

Executor threadPoolExecutor = Executors.newFixedThreadPool(4);
private interface HashCallback {
    void onHashCalculated(@Nullable String hash);
}

boolean hashRunning = calculateHash(inputStream, threadPoolExecutor, hash -> {
    if (Objects.equals(hash, expectedHash)) {
        // Work with the content.
    }
});

if (!hashRunning) {
    // There was an error setting up the hash function.
}

private boolean calculateHash(@NonNull InputStream stream,
                              @NonNull Executor executor,
                              @NonNull HashCallback hashCallback) {
    final MessageDigest digest;
    try {
        digest = MessageDigest.getInstance("SHA-512");
    } catch (NoSuchAlgorithmException nsa) {
        return false;
    }

    // Calculating the hash code can take quite a bit of time, so it shouldn't
    // be done on the main thread.
    executor.execute(() -> {
        String hash;
        try (DigestInputStream digestStream =
                new DigestInputStream(stream, digest)) {
            while (digestStream.read() != -1) {
                // The DigestInputStream does the work; nothing for us to do.
            }
            StringBuilder builder = new StringBuilder();
            for (byte aByte : digest.digest()) {
                builder.append(String.format("%02x", aByte)).append(':');
            }
            hash = builder.substring(0, builder.length() - 1);
        } catch (IOException e) {
            hash = null;
        }

        final String calculatedHash = hash;
        runOnUiThread(() -> hashCallback.onHashCalculated(calculatedHash));
    });
    return true;
}

ক্যাশে ফাইলগুলিতে শুধুমাত্র অ-সংবেদনশীল ডেটা সংরক্ষণ করুন

অ-সংবেদনশীল অ্যাপ ডেটাতে দ্রুত অ্যাক্সেস প্রদান করতে, এটি ডিভাইসের ক্যাশে সংরক্ষণ করুন। 1 MB এর চেয়ে বড় ক্যাশেগুলির জন্য, getExternalCacheDir() ব্যবহার করুন। 1 MB বা ছোট ক্যাশেগুলির জন্য, getCacheDir() ব্যবহার করুন৷ উভয় পদ্ধতিই আপনাকে File অবজেক্ট প্রদান করে যাতে আপনার অ্যাপের ক্যাশে করা ডেটা থাকে।

নিম্নলিখিত কোড স্নিপেট দেখায় যে আপনার অ্যাপ সম্প্রতি ডাউনলোড করা একটি ফাইল কীভাবে ক্যাশে করবেন:

কোটলিন

val cacheFile = File(myDownloadedFileUri).let { fileToCache ->
    File(cacheDir.path, fileToCache.name)
}

জাভা

File cacheDir = getCacheDir();
File fileToCache = new File(myDownloadedFileUri);
String fileToCacheName = fileToCache.getName();
File cacheFile = new File(cacheDir.getPath(), fileToCacheName);

দ্রষ্টব্য: আপনি শেয়ার্ড স্টোরেজের মধ্যে আপনার অ্যাপের ক্যাশে রাখার জন্য getExternalCacheDir() ব্যবহার করলে, আপনার অ্যাপ চলাকালীন ব্যবহারকারী এই স্টোরেজ ধারণকারী মিডিয়া বের করে দিতে পারে। এই ব্যবহারকারীর আচরণের কারণে ক্যাশে মিসকে সুন্দরভাবে পরিচালনা করার জন্য যুক্তি অন্তর্ভুক্ত করুন।

সতর্কতা: এই ফাইলগুলিতে কোন নিরাপত্তা বলবৎ নেই। তাই, যেকোন অ্যাপ যেটি Android 10 (API লেভেল 29) বা তার নিচের দিকে লক্ষ্য করে এবং WRITE_EXTERNAL_STORAGE অনুমতি আছে তারা এই ক্যাশের বিষয়বস্তু অ্যাক্সেস করতে পারে।

সম্পর্কিত তথ্য: ডেটা এবং ফাইল স্টোরেজ ওভারভিউ

ব্যক্তিগত মোডে SharedPreferences ব্যবহার করুন

আপনার অ্যাপের SharedPreferences অবজেক্ট তৈরি বা অ্যাক্সেস করতে getSharedPreferences() ব্যবহার করার সময়, MODE_PRIVATE ব্যবহার করুন। এইভাবে, শুধুমাত্র আপনার অ্যাপ শেয়ার করা পছন্দ ফাইলের মধ্যে তথ্য অ্যাক্সেস করতে পারে।

আপনি যদি সমস্ত অ্যাপ জুড়ে ডেটা ভাগ করতে চান, তাহলে SharedPreferences অবজেক্ট ব্যবহার করবেন না। পরিবর্তে, অ্যাপ্লিকেশানগুলিতে নিরাপদে ডেটা ভাগ করতে পদক্ষেপগুলি অনুসরণ করুন৷

সিকিউরিটি লাইব্রেরি এনক্রিপ্টেড শেয়ারডপ্রেফারেন্স ক্লাসও প্রদান করে যা শেয়ারডপ্রেফারেন্স ক্লাসকে মোড়ানো হয় এবং কী এবং মানগুলি স্বয়ংক্রিয়ভাবে এনক্রিপ্ট করে।

সম্পর্কিত তথ্য:

পরিষেবা এবং নির্ভরতা আপ টু ডেট রাখুন

বেশিরভাগ অ্যাপ বিশেষায়িত কাজগুলি সম্পূর্ণ করতে বাহ্যিক লাইব্রেরি এবং ডিভাইস সিস্টেম তথ্য ব্যবহার করে। আপনার অ্যাপের নির্ভরতা আপ টু ডেট রেখে, আপনি যোগাযোগের এই পয়েন্টগুলিকে আরও সুরক্ষিত করে তোলেন৷

Google Play পরিষেবা নিরাপত্তা প্রদানকারী চেক করুন

দ্রষ্টব্য: এই বিভাগটি শুধুমাত্র এমন অ্যাপগুলির জন্য প্রযোজ্য যেগুলিকে লক্ষ্য করে এমন ডিভাইসগুলিতে Google Play পরিষেবাগুলি ইনস্টল করা আছে৷

যদি আপনার অ্যাপটি Google Play পরিষেবা ব্যবহার করে, তাহলে নিশ্চিত করুন যে আপনার অ্যাপটি ইনস্টল করা ডিভাইসে এটি আপডেট করা আছে। UI থ্রেডের বাইরে, অ্যাসিঙ্ক্রোনাসভাবে চেকটি সম্পাদন করুন। ডিভাইসটি আপ টু ডেট না হলে, একটি অনুমোদন ত্রুটি ট্রিগার করুন।

আপনার অ্যাপটি যে ডিভাইসে ইনস্টল করা আছে সেখানে Google Play পরিষেবাগুলি আপ টু ডেট আছে কিনা তা নির্ধারণ করতে, SSL শোষণের বিরুদ্ধে সুরক্ষার জন্য আপনার নিরাপত্তা প্রদানকারীকে আপডেট করার বিষয়ে নির্দেশিত পদক্ষেপগুলি অনুসরণ করুন৷

সম্পর্কিত তথ্য:

সমস্ত অ্যাপ নির্ভরতা আপডেট করুন

আপনার অ্যাপ স্থাপন করার আগে, নিশ্চিত করুন যে সমস্ত লাইব্রেরি, SDK এবং অন্যান্য নির্ভরতা আপ টু ডেট আছে:

  • Android SDK-এর মতো প্রথম-পক্ষ নির্ভরতার জন্য, Android স্টুডিওতে পাওয়া আপডেট করার সরঞ্জামগুলি ব্যবহার করুন, যেমন SDK ম্যানেজার
  • তৃতীয় পক্ষের নির্ভরতাগুলির জন্য, আপনার অ্যাপ ব্যবহার করে এমন লাইব্রেরিগুলির ওয়েবসাইটগুলি পরীক্ষা করুন এবং উপলব্ধ আপডেট এবং নিরাপত্তা প্যাচগুলি ইনস্টল করুন৷

সম্পর্কিত তথ্য: বিল্ড নির্ভরতা যোগ করুন

আরও তথ্য

কীভাবে আপনার অ্যাপকে আরও সুরক্ষিত করা যায় সে সম্পর্কে আরও জানতে, নিম্নলিখিত সংস্থানগুলি দেখুন: