बाहरी स्टोरेज में सेव किया गया संवेदनशील डेटा

OWASP कैटगरी: MASVS-स्टोरेज: स्टोरेज

खास जानकारी

Android 10 (एपीआई लेवल 29) या इससे पहले के वर्शन को टारगेट करने वाले ऐप्लिकेशन, स्कोप किए गए स्टोरेज का इस्तेमाल नहीं करते. इसका मतलब है कि बाहरी स्टोरेज में सेव किया गया कोई भी डेटा READ_EXTERNAL_STORAGE के साथ किसी भी दूसरे ऐप्लिकेशन से ऐक्सेस किया गया अनुमति.

असर

Android 10 (एपीआई 29) या इससे पहले के वर्शन को टारगेट करने वाले ऐप्लिकेशन में, अगर संवेदनशील डेटा बाहरी स्टोरेज में सेव किया गया है, तो डिवाइस पर मौजूद READ_EXTERNAL_STORAGE अनुमति वाला कोई भी ऐप्लिकेशन उसे ऐक्सेस कर सकता है. यह नुकसान पहुंचाने वाले कॉन्टेंट को अनुमति देता है ऐसे ऐप्लिकेशन जो संवेदनशील फ़ाइलों को हमेशा या कुछ समय के लिए, बिना किसी रुकावट के ऐक्सेस कर सकते हैं बाहरी स्टोरेज पर सेव होता है. इसके अतिरिक्त, चूंकि बाहरी सामग्री पर की जगह को सिस्टम पर मौजूद किसी भी ऐप्लिकेशन, नुकसान पहुंचाने वाले ऐसे ऐप्लिकेशन से ऐक्सेस किया जा सकता है जो यह भी बताता है कि WRITE_EXTERNAL_STORAGE अनुमति, सेव की गई फ़ाइलों के साथ छेड़छाड़ कर सकती है पर, जैसे कि नुकसान पहुंचाने वाला डेटा शामिल करने के लिए किया जा सकता है. यह नुकसान पहुंचाने वाला ऐप्लिकेशन में लोड किए जाने पर, डेटा को उपयोगकर्ताओं को धोखा देने या कोड निष्पादन को पूरा करें.

जोखिम कम करने के तरीके

सीमित स्टोरेज (Android 10 और उसके बाद के वर्शन)

Android 10

Android 10 को टारगेट करने वाले ऐप्लिकेशन के लिए, डेवलपर साफ़ तौर पर स्कोप वाले स्टोरेज के लिए ऑप्ट-इन कर सकते हैं. ऐसा करने के लिए, requestLegacyExternalStorage को गलत पर फ़्लैग करें. AndroidManifest.xml फ़ाइल. स्कोप वाले स्टोरेज की मदद से, ऐप्लिकेशन सिर्फ़ उन फ़ाइलों को ऐक्सेस कर सकते हैं जिन्हें उन्होंने बाहरी स्टोरेज में खुद बनाया है. इसके अलावा, वे MediaStore API का इस्तेमाल करके सेव की गई फ़ाइलों को भी ऐक्सेस कर सकते हैं. जैसे, ऑडियो और वीडियो. यह उपयोगकर्ता की निजता और सुरक्षा को बनाए रखने में मदद करता है.

Android 11 और उसके बाद के वर्शन

Android 11 या उसके बाद के वर्शन को टारगेट करने वाले ऐप्लिकेशन के लिए, ओएस स्कोप वाली मेमोरी का इस्तेमाल करता है. इसका मतलब है कि यह मेमोरी को अनदेखा करता है requestLegacyExternalStorage फ़्लैग करता है और अपने-आप सुरक्षा करता है ऐप्लिकेशन की अनचाहे ऐक्सेस से बाहरी स्टोरेज.

संवेदनशील जानकारी के लिए, डिवाइस का स्टोरेज इस्तेमाल करें

टारगेट किए गए Android वर्शन के बावजूद, किसी ऐप्लिकेशन का संवेदनशील डेटा हमेशा डिवाइस के स्टोरेज में सेव किया जाना चाहिए. Android सैंडबॉक्सिंग की मदद से, डिवाइस के इंटरनल स्टोरेज का ऐक्सेस, मालिकाना हक वाले ऐप्लिकेशन के लिए अपने-आप सीमित हो जाता है. इसलिए, जब तक डिवाइस को रूट नहीं किया जाता, तब तक इसे सुरक्षित माना जा सकता है.

संवेदनशील डेटा को एन्क्रिप्ट करना

अगर ऐप्लिकेशन के इस्तेमाल के उदाहरण के लिए, बाहरी स्टोरेज पर संवेदनशील जानकारी सेव करना ज़रूरी हो तो डेटा एन्क्रिप्ट किया जाना चाहिए. हमारा सुझाव है कि आप एन्क्रिप्शन के लिए मज़बूत एल्गोरिदम का इस्तेमाल करें. साथ ही, कुंजी को सुरक्षित तरीके से सेव करने के लिए, Android कीस्टोर का इस्तेमाल करें.

आम तौर पर, सुरक्षा के लिए सभी संवेदनशील डेटा को एन्क्रिप्ट (सुरक्षित) करने का सुझाव दिया जाता है. इससे कोई फ़र्क़ नहीं पड़ता कि डेटा कहां सेव किया गया है.

ध्यान रखें कि फ़ुल डिस्क एन्क्रिप्शन (या Android 10 से फ़ाइल-आधारित एन्क्रिप्शन) एक ऐसा तरीका है जिसका मकसद डेटा को फ़िज़िकल ऐक्सेस और हमले के अन्य तरीकों से सुरक्षित रखना है. इसलिए, सुरक्षा के एक जैसे उपाय के लिए, ऐप्लिकेशन को एक्सटर्नल स्टोरेज में मौजूद संवेदनशील डेटा को भी एन्क्रिप्ट करना चाहिए.

इंटिग्रिटी जांच करें

ऐसे मामलों में जहां बाहरी स्टोरेज से डेटा या कोड को ऐप्लिकेशन, इंटिग्रिटी जांच करके यह पुष्टि की जाती है कि किसी अन्य ऐप्लिकेशन ने छेड़छाड़ नहीं की है का सुझाव दिया जाता है. फ़ाइलों के हैश को सुरक्षित तरीके से सेव किया जाना चाहिए. इसके लिए, उन्हें एन्क्रिप्ट करके डिवाइस के स्टोरेज में सेव करना सबसे अच्छा होता है.

Kotlin

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!")
        }
    }
}

Java

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!");
        }
    }
}

संसाधन