বাহ্যিক স্টোরেজে সংরক্ষিত সংবেদনশীল ডেটা

OWASP বিভাগ: MASVS-STORAGE: স্টোরেজ

সংক্ষিপ্ত বিবরণ

অ্যান্ড্রয়েড ১০ (এপিআই ২৯) বা তার নিচের সংস্করণের জন্য তৈরি অ্যাপ্লিকেশনগুলো স্কোপড স্টোরেজ প্রয়োগ করে না। এর মানে হলো, এক্সটার্নাল স্টোরেজে সংরক্ষিত যেকোনো ডেটা READ_EXTERNAL_STORAGE পারমিশনযুক্ত অন্য যেকোনো অ্যাপ্লিকেশন অ্যাক্সেস করতে পারে।

প্রভাব

অ্যান্ড্রয়েড ১০ (এপিআই ২৯) বা তার নিচের সংস্করণের জন্য তৈরি অ্যাপ্লিকেশনগুলিতে, যদি এক্সটার্নাল স্টোরেজে সংবেদনশীল ডেটা সংরক্ষিত থাকে, তবে ডিভাইসের READ_EXTERNAL_STORAGE পারমিশন থাকা যেকোনো অ্যাপ্লিকেশন তা অ্যাক্সেস করতে পারে। এর ফলে ক্ষতিকারক অ্যাপ্লিকেশনগুলি এক্সটার্নাল স্টোরেজে স্থায়ীভাবে বা অস্থায়ীভাবে সংরক্ষিত সংবেদনশীল ফাইলগুলি নীরবে অ্যাক্সেস করতে পারে। এছাড়াও, যেহেতু সিস্টেমের যেকোনো অ্যাপ এক্সটার্নাল স্টোরেজের কন্টেন্ট অ্যাক্সেস করতে পারে, তাই WRITE_EXTERNAL_STORAGE পারমিশন থাকা যেকোনো ক্ষতিকারক অ্যাপ্লিকেশন এক্সটার্নাল স্টোরেজে সংরক্ষিত ফাইলগুলির সাথে কারসাজি করতে পারে, যেমন ক্ষতিকারক ডেটা অন্তর্ভুক্ত করার জন্য। এই ক্ষতিকারক ডেটা, যদি অ্যাপ্লিকেশনে লোড করা হয়, তবে তা ব্যবহারকারীদের ধোঁকা দেওয়ার জন্য বা এমনকি কোড এক্সিকিউশন ঘটানোর জন্যও ডিজাইন করা হতে পারে।

প্রশমন

স্কোপড স্টোরেজ (অ্যান্ড্রয়েড ১০ এবং পরবর্তী সংস্করণ)

অ্যান্ড্রয়েড ১০

অ্যান্ড্রয়েড ১০-এর জন্য তৈরি অ্যাপ্লিকেশনগুলোতে, ডেভেলপাররা স্কোপড স্টোরেজ ব্যবহারের জন্য স্পষ্টভাবে সম্মতি জানাতে পারেন। AndroidManifest.xml ফাইলে requestLegacyExternalStorage ফ্ল্যাগটিকে false সেট করার মাধ্যমে এটি করা যায়। স্কোপড স্টোরেজের মাধ্যমে, অ্যাপ্লিকেশনগুলো এক্সটার্নাল স্টোরেজে শুধুমাত্র তাদের নিজেদের তৈরি করা ফাইল অথবা MediaStore API ব্যবহার করে সংরক্ষিত ফাইল টাইপ, যেমন অডিও এবং ভিডিও, অ্যাক্সেস করতে পারে। এটি ব্যবহারকারীর গোপনীয়তা এবং নিরাপত্তা রক্ষা করতে সাহায্য করে।

অ্যান্ড্রয়েড ১১ এবং তার পরবর্তী সংস্করণ

অ্যান্ড্রয়েড ১১ বা তার পরবর্তী সংস্করণগুলোর জন্য তৈরি অ্যাপ্লিকেশনগুলোতে, অপারেটিং সিস্টেম স্কোপড স্টোরেজ ব্যবহার বাধ্যতামূলক করে , অর্থাৎ এটি ` requestLegacyExternalStorage ফ্ল্যাগটিকে উপেক্ষা করে এবং অ্যাপ্লিকেশনগুলোর এক্সটার্নাল স্টোরেজকে অনাকাঙ্ক্ষিত অ্যাক্সেস থেকে স্বয়ংক্রিয়ভাবে সুরক্ষিত রাখে।

সংবেদনশীল ডেটার জন্য অভ্যন্তরীণ স্টোরেজ ব্যবহার করুন

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

সংবেদনশীল ডেটা এনক্রিপ্ট করুন

যদি অ্যাপ্লিকেশনটির ব্যবহারের জন্য এক্সটার্নাল স্টোরেজে সংবেদনশীল ডেটা সংরক্ষণের প্রয়োজন হয়, তবে ডেটা এনক্রিপ্ট করা উচিত। একটি শক্তিশালী এনক্রিপশন অ্যালগরিদম ব্যবহার করার পরামর্শ দেওয়া হয় এবং কী (key) নিরাপদে সংরক্ষণ করার জন্য অ্যান্ড্রয়েড কীস্টোর (Android KeyStore) ব্যবহার করা যেতে পারে।

সাধারণভাবে, সমস্ত সংবেদনশীল তথ্য এনক্রিপ্ট করা একটি প্রস্তাবিত নিরাপত্তা অনুশীলন, তা যেখানেই সংরক্ষণ করা হোক না কেন।

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

অখণ্ডতা যাচাই করুন

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

কোটলিন

package com.example.myapplication

import java.io.BufferedInputStream
import java.io.FileInputStream
import java.io.IOException
import java.security.MessageDigest
import java.security.NoSuchAlgorithmException

object FileIntegrityChecker {
    @Throws(IOException::class, NoSuchAlgorithmException::class)
    fun getIntegrityHash(filePath: String?): String {
        val md = MessageDigest.getInstance("SHA-256") // You can choose other algorithms as needed
        val buffer = ByteArray(8192)
        var bytesRead: Int
        BufferedInputStream(FileInputStream(filePath)).use { fis ->
            while (fis.read(buffer).also { bytesRead = it } != -1) {
                md.update(buffer, 0, bytesRead)
            }

    }

    private fun bytesToHex(bytes: ByteArray): String {
        val sb = StringBuilder()
        for (b in bytes) {
            sb.append(String.format("%02x", b))
        }
        return sb.toString()
    }

    @Throws(IOException::class, NoSuchAlgorithmException::class)
    fun verifyIntegrity(filePath: String?, expectedHash: String): Boolean {
        val actualHash = getIntegrityHash(filePath)
        return actualHash == expectedHash
    }

    @Throws(Exception::class)
    @JvmStatic
    fun main(args: Array<String>) {
        val filePath = "/path/to/your/file"
        val expectedHash = "your_expected_hash_value"
        if (verifyIntegrity(filePath, expectedHash)) {
            println("File integrity is valid!")
        } else {
            println("File integrity is compromised!")
        }
    }
}

জাভা

package com.example.myapplication;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class FileIntegrityChecker {

    public static String getIntegrityHash(String filePath) throws IOException, NoSuchAlgorithmException {
        MessageDigest md = MessageDigest.getInstance("SHA-256"); // You can choose other algorithms as needed
        byte[] buffer = new byte[8192];
        int bytesRead;

        try (BufferedInputStream fis = new BufferedInputStream(new FileInputStream(filePath))) {
            while ((bytesRead = fis.read(buffer)) != -1) {
                md.update(buffer, 0, bytesRead);
            }
        }

        byte[] digest = md.digest();
        return bytesToHex(digest);
    }

    private static String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }

    public static boolean verifyIntegrity(String filePath, String expectedHash) throws IOException, NoSuchAlgorithmException {
        String actualHash = getIntegrityHash(filePath);
        return actualHash.equals(expectedHash);
    }

    public static void main(String[] args) throws Exception {
        String filePath = "/path/to/your/file";
        String expectedHash = "your_expected_hash_value";

        if (verifyIntegrity(filePath, expectedHash)) {
            System.out.println("File integrity is valid!");
        } else {
            System.out.println("File integrity is compromised!");
        }
    }
}

সম্পদ