OWASP कैटगरी: MASVS-STORAGE: स्टोरेज
खास जानकारी
लॉग की जानकारी का खुलासा एक तरह की गड़बड़ी है. इसमें ऐप्लिकेशन, डिवाइस के लॉग में संवेदनशील डेटा प्रिंट करते हैं. अगर यह संवेदनशील जानकारी, गलत इरादे वाले लोगों के हाथ लग जाती है, तो यह सीधे तौर पर उनके काम की हो सकती है. जैसे, उपयोगकर्ता के क्रेडेंशियल या निजी तौर पर पहचान की जा सकने वाली जानकारी (पीआईआई). इसके अलावा, इसकी मदद से और भी हमले किए जा सकते हैं.
यह समस्या, इन स्थितियों में हो सकती है:
- ऐप्लिकेशन से जनरेट किए गए लॉग:
- लॉग में, अनधिकृत लोगों को ऐक्सेस देने की अनुमति होती है. हालांकि, इनमें गलती से संवेदनशील डेटा शामिल हो जाता है.
- लॉग में जान-बूझकर संवेदनशील डेटा शामिल किया जाता है, लेकिन गलती से अनधिकृत लोगों के पास इसका ऐक्सेस चला जाता है.
- सामान्य गड़बड़ी के लॉग. इनमें कभी-कभी संवेदनशील डेटा प्रिंट हो सकता है. यह इस बात पर निर्भर करता है कि गड़बड़ी का कौनसा मैसेज ट्रिगर हुआ है.
- बाहर से जनरेट किए गए लॉग:
- बाहरी कॉम्पोनेंट, संवेदनशील डेटा वाले लॉग प्रिंट करते हैं.
Android के Log.* स्टेटमेंट, सामान्य मेमोरी बफ़र logcat में लिखते हैं. Android 4.1 (एपीआई लेवल 16) के बाद से, सिर्फ़ खास अधिकारों वाले सिस्टम ऐप्लिकेशन को READ_LOGS की अनुमति देकर, logcat को पढ़ने का ऐक्सेस दिया जा सकता है. हालांकि, Android कई तरह के डिवाइसों के साथ काम करता है. इनमें पहले से लोड किए गए ऐप्लिकेशन, कभी-कभी READ_LOGS के खास अधिकार का एलान करते हैं. इसलिए, सीधे logcat में लॉग करने से बचने का सुझाव दिया जाता है, क्योंकि इससे डेटा लीक होने की संभावना ज़्यादा होती है.
पक्का करें कि आपके ऐप्लिकेशन के डीबग न किए गए वर्शन में, logcat में लॉग किया गया सारा डेटा साफ़ किया गया हो. ऐसा कोई भी डेटा हटाएं जो संवेदनशील हो सकता है. अतिरिक्त सावधानी के तौर पर, R8 जैसे टूल का इस्तेमाल करके, चेतावनी और गड़बड़ी के अलावा, लॉग के सभी लेवल हटाएं. अगर आपको ज़्यादा जानकारी वाले लॉग चाहिए, तो सिस्टम लॉग का इस्तेमाल करने के बजाय, इंटरनल स्टोरेज का इस्तेमाल करें और अपने लॉग सीधे मैनेज करें.
असर
लॉग की जानकारी के खुलासे से जुड़ी गड़बड़ी की गंभीरता, संदर्भ और संवेदनशील डेटा के टाइप के हिसाब से अलग-अलग हो सकती है.कुल मिलाकर, इस गड़बड़ी की वजह से, पीआईआई और क्रेडेंशियल जैसी ज़रूरी जानकारी की गोपनीयता खत्म हो जाती है
गड़बड़ी को ठीक करने के तरीके
सामान्य
डिज़ाइन और लागू करने के दौरान, सामान्य तौर पर पहले से ही सावधानी बरतने के लिए, कम से कम अधिकारों के सिद्धांत के मुताबिक, भरोसे की सीमाएं तय करें. सबसे सही तरीका यह है कि संवेदनशील डेटा, भरोसे वाले किसी भी इलाके से बाहर न जाए या वहां तक न पहुंचे. इससे, अधिकारों को अलग-अलग रखने की नीति मज़बूत होती है.
संवेदनशील डेटा लॉग न करें. सिर्फ़ कंपाइल-टाइम कॉन्स्टैंट लॉग करें. हालांकि, ऐसा तब करें, जब यह मुमकिन हो. कंपाइल-टाइम कॉन्स्टैंट एनोटेशन के लिए, ErrorProne टूल का इस्तेमाल किया जा सकता है.
ऐसे लॉग से बचें जिनमें ऐसे स्टेटमेंट प्रिंट होते हैं जिनमें अनचाही जानकारी शामिल हो सकती है. इसमें संवेदनशील डेटा भी शामिल है. यह इस बात पर निर्भर करता है कि कौनसा गड़बड़ी का मैसेज ट्रिगर हुआ है. लॉग और गड़बड़ी के लॉग में प्रिंट किए गए डेटा में, सिर्फ़ अनुमान के मुताबिक जानकारी शामिल होनी चाहिए.
logcat में लॉग करने से बचें. ऐसा इसलिए, क्योंकि logcat में लॉग करने से निजता से जुड़ी समस्या हो सकती है. ऐसा उन ऐप्लिकेशन की वजह से हो सकता है जिनके पास READ_LOGS की अनुमति है. यह इसलिए भी असरदार नहीं है, क्योंकि इससे चेतावनियां ट्रिगर नहीं की जा सकतीं या क्वेरी नहीं की जा सकती. हमारा सुझाव है कि ऐप्लिकेशन, डेवलपर के लिए बनाए गए वर्शन के लिए ही logcat बैकएंड कॉन्फ़िगर करें.
लॉग मैनेज करने वाली ज़्यादातर लाइब्रेरी में, लॉग के लेवल तय किए जा सकते हैं. इससे डीबग और प्रोडक्शन लॉग के बीच, अलग-अलग मात्रा में जानकारी लॉग की जा सकती है. प्रॉडक्ट की टेस्टिंग खत्म होने के तुरंत बाद, लॉग का लेवल बदलें, ताकि यह "डीबग" से अलग हो.
प्रोडक्शन से, लॉग के ज़्यादा से ज़्यादा लेवल हटाएं. अगर प्रोडक्शन में लॉग रखना ज़रूरी है, तो लॉग स्टेटमेंट से, नॉन-कॉन्स्टैंट वैरिएबल हटाएं. ये स्थितियां हो सकती हैं:
- आपके पास प्रोडक्शन से सभी लॉग हटाने का विकल्प है.
- आपको प्रोडक्शन में, चेतावनी और गड़बड़ी के लॉग रखने होंगे.
इन दोनों स्थितियों में, R8 जैसी लाइब्रेरी का इस्तेमाल करके, लॉग अपने-आप हटाएं. लॉग को मैन्युअल तरीके से हटाने की कोशिश करने पर, गड़बड़ी होने की संभावना होती है. कोड ऑप्टिमाइज़ेशन के तहत, R8 को इस तरह सेट किया जा सकता है कि वह लॉग के उन लेवल को सुरक्षित तरीके से हटा दे जिन्हें आपको डीबग करने के लिए रखना है, लेकिन प्रोडक्शन में नहीं.
अगर आपको प्रोडक्शन में लॉग करना है, तो ऐसे फ़्लैग तैयार करें जिनका इस्तेमाल, किसी घटना के होने पर, लॉगिंग को बंद करने के लिए किया जा सके. घटना के जवाब देने वाले फ़्लैग में, इन बातों को प्राथमिकता दी जानी चाहिए: डिप्लॉयमेंट की सुरक्षा; डिप्लॉयमेंट की स्पीड और आसानी; लॉग को पूरी तरह से हटाने की सुविधा; मेमोरी का इस्तेमाल; और हर लॉग मैसेज को स्कैन करने की परफ़ॉर्मेंस लागत.
R8 का इस्तेमाल करके, प्रोडक्शन बिल्ड से `logcat` में लॉग हटाएं.
Android Studio 3.4 या Android Gradle प्लगिन 3.4.0 और इसके बाद के वर्शन में, R8, कोड ऑप्टिमाइज़ेशन और श्रिंकिंग के लिए डिफ़ॉल्ट कंपाइलर है. हालांकि, आपको R8 को चालू करना होगा.
R8 ने ProGuard की जगह ले ली है. हालांकि, प्रोजेक्ट के रूट फ़ोल्डर में मौजूद नियमों वाली फ़ाइल को अब भी proguard-rules.pro कहा जाता है. यहां दिया गया स्निपेट, proguard-rules.pro फ़ाइल का एक उदाहरण दिखाता है. इससे प्रोडक्शन से, चेतावनियों और गड़बड़ियों को छोड़कर सभी लॉग हटाए जाते हैं:
-assumenosideeffects class android.util.Log {
private static final String TAG = "MyTAG";
public static boolean isLoggable(java.lang.String, int);
public static int v(TAG, "My log as verbose");
public static int d(TAG, "My log as debug");
public static int i(TAG, "My log as information");
}
यहां दी गई proguard-rules.pro फ़ाइल के उदाहरण से, प्रोडक्शन से सभी लॉग हटाए जाते हैं:
-assumenosideeffects class android.util.Log {
private static final String TAG = "MyTAG";
public static boolean isLoggable(java.lang.String, int);
public static int v(TAG, "My log as verbose");
public static int d(TAG, "My log as debug");
public static int i(TAG, "My log as information");
public static int w(TAG, "My log as warning");
public static int e(TAG, "My log as error");
}
ध्यान दें कि R8, ऐप्लिकेशन को श्रिंक करने की सुविधाएं और लॉग हटाने की सुविधा देता है. अगर आपको R8 का इस्तेमाल सिर्फ़ लॉग हटाने की सुविधा के लिए करना है, तो अपनी proguard-rules.pro फ़ाइल में यह जानकारी जोड़ें:
-dontwarn **
-dontusemixedcaseclassnames
-dontskipnonpubliclibraryclasses
-dontpreverify
-verbose
-optimizations !code/simplification/arithmetic,!code/allocation/variable
-keep class **
-keepclassmembers class *{*;}
-keepattributes *
प्रोडक्शन में मौजूद, संवेदनशील डेटा वाले किसी भी लॉग को साफ़ करें
संवेदनशील डेटा लीक होने से बचाने के लिए, पक्का करें कि आपके ऐप्लिकेशन के डीबग न किए गए वर्शन में, logcat में लॉग किया गया सारा डेटा साफ़ किया गया हो. ऐसा कोई भी डेटा हटाएं जो संवेदनशील हो सकता है.
उदाहरण:
Kotlin
data class Credential<T>(val data: String) {
/** Returns a redacted value to avoid accidental inclusion in logs. */
override fun toString() = "Credential XX"
}
fun checkNoMatches(list: List<Any>) {
if (!list.isEmpty()) {
Log.e(TAG, "Expected empty list, but was %s", list)
}
}
Java
public class Credential<T> {
private T t;
/** Returns a redacted value to avoid accidental inclusion in logs. */
public String toString(){
return "Credential XX";
}
}
private void checkNoMatches(List<E> list) {
if (!list.isEmpty()) {
Log.e(TAG, "Expected empty list, but was %s", list);
}
}
लॉग में मौजूद संवेदनशील डेटा को हटाएं
अगर आपको अपने लॉग में संवेदनशील डेटा शामिल करना है, तो हमारा सुझाव है कि संवेदनशील डेटा को हटाने या छिपाने के लिए, लॉग को प्रिंट करने से पहले उन्हें साफ़ करें. इसके लिए, इनमें से कोई एक तरीका अपनाएं:
- टोकनाइज़ेशन. अगर संवेदनशील डेटा, वॉल्ट में सेव है, तो संवेदनशील डेटा के बजाय टोकन लॉग करें. जैसे, एन्क्रिप्शन मैनेजमेंट सिस्टम, जिससे टोकन के ज़रिए सीक्रेट रेफ़र किए जा सकते हैं.
- डेटा मास्किंग. डेटा मास्किंग, एकतरफ़ा और ऐसी प्रोसेस है जिसे वापस नहीं किया जा सकता. इससे संवेदनशील डेटा का ऐसा वर्शन बनता है जो मूल डेटा जैसा दिखता है. हालांकि, इसमें फ़ील्ड में मौजूद सबसे संवेदनशील जानकारी छिपी होती है. उदाहरण: क्रेडिट कार्ड नंबर
1234-5678-9012-3456कोXXXX-XXXX-XXXX-1313से बदलना. हमारा सुझाव है कि अपने ऐप्लिकेशन को प्रोडक्शन में रिलीज़ करने से पहले, सुरक्षा की समीक्षा की प्रोसेस पूरी करें, ताकि डेटा मास्किंग के इस्तेमाल की जांच की जा सके. चेतावनी: डेटा मास्किंग का इस्तेमाल उन मामलों में न करें जहां संवेदनशील डेटा का सिर्फ़ एक हिस्सा रिलीज़ करने से भी सुरक्षा पर काफ़ी असर पड़ सकता है. जैसे, पासवर्ड मैनेज करते समय. - रिडक्शन. रिडक्शन, मास्किंग की तरह ही होता है. हालांकि, इससे फ़ील्ड में मौजूद सारी जानकारी छिप जाती है. उदाहरण: क्रेडिट कार्ड नंबर
1234-5678-9012-3456कोXXXX-XXXX-XXXX-XXXXसे बदलना. - फ़िल्टर करना. अगर आपकी चुनी हुई लॉगिंग लाइब्रेरी में फ़ॉर्मैट स्ट्रिंग पहले से मौजूद नहीं हैं, तो उन्हें लागू करें. इससे लॉग स्टेटमेंट में, नॉन-कॉन्स्टैंट वैल्यू में बदलाव करना आसान हो जाता है.
लॉग प्रिंट करने की प्रोसेस, सिर्फ़ “लॉग सैनिटाइज़र” कॉम्पोनेंट के ज़रिए की जानी चाहिए. यह कॉम्पोनेंट, लॉग को प्रिंट करने से पहले उन्हें साफ़ करता है. जैसा कि यहां दिए गए कोड स्निपेट में दिखाया गया है.
Kotlin
data class ToMask<T>(private val data: T) {
// Prevents accidental logging when an error is encountered.
override fun toString() = "XX"
// Makes it more difficult for developers to invoke sensitive data
// and facilitates sensitive data usage tracking.
fun getDataToMask(): T = data
}
data class Person(
val email: ToMask<String>,
val username: String
)
fun main() {
val person = Person(
ToMask("name@gmail.com"),
"myname"
)
println(person)
println(person.email.getDataToMask())
}
Java
public class ToMask<T> {
// Prevents accidental logging when an error is encountered.
public String toString(){
return "XX";
}
// Makes it more difficult for developers to invoke sensitive data
// and facilitates sensitive data usage tracking.
public T getDataToMask() {
return this;
}
}
public class Person {
private ToMask<String> email;
private String username;
public Person(ToMask<String> email, String username) {
this.email = email;
this.username = username;
}
}
public static void main(String[] args) {
Person person = new Person(
ToMask("name@gmail.com"),
"myname"
);
System.out.println(person);
System.out.println(person.email.getDataToMask());
}