OWASP कैटगरी: MASVS-PLATFORM: प्लैटफ़ॉर्म इंटरैक्शन
खास जानकारी
दस्तावेज़ के मुताबिक, ContentResolver
एक “क्लास है, जो ऐप्लिकेशन को कॉन्टेंट मॉडल का ऐक्सेस देती है”. ContentResolvers, इनसे मिले कॉन्टेंट के साथ इंटरैक्ट करने, उसे फ़ेच करने या उसमें बदलाव करने के तरीके दिखाते हैं:
- इंस्टॉल किए गए ऐप्लिकेशन (
content://
यूआरआई स्कीम) - फ़ाइल सिस्टम (
file://
यूआरआई स्कीम) - Android (
android.resource://
यूआरआई स्कीम) के ज़रिए दिए गए एपीआई का इस्तेमाल किया जा सकता है.
खास जानकारी के तौर पर, ContentResolver
से जुड़ी कमजोरियां कन्फ़्यूज़्ड डिप्टी क्लास से जुड़ी होती हैं. ऐसा इसलिए, क्योंकि हमलावर, सुरक्षित कॉन्टेंट को ऐक्सेस करने के लिए, कमजोर ऐप्लिकेशन की विशेषताओं का इस्तेमाल कर सकता है.
जोखिम: भरोसेमंद नहीं होने वाले file:// यूआरआई का गलत इस्तेमाल
file://
यूआरआई की जोखिम की आशंका का इस्तेमाल करके, ContentResolver
का गलत इस्तेमाल करने से, यूआरआई से बताए गए फ़ाइल डिस्क्रिप्टर को दिखाने की ContentResolver
की क्षमता का गलत इस्तेमाल किया जाता है. इस समस्या का असर, ContentResolver
एपीआई के openFile()
, openFileDescriptor()
, openInputStream()
, openOutputStream()
या openAssetFileDescriptor()
जैसे फ़ंक्शन पर पड़ता है. इस समस्या का गलत इस्तेमाल, पूरी तरह या कुछ हद तक हमलावर के कंट्रोल वाले file://
यूआरआई की मदद से किया जा सकता है. इससे, ऐप्लिकेशन को ऐसी फ़ाइलों को ऐक्सेस करने के लिए मजबूर किया जा सकता है जिन्हें ऐक्सेस नहीं किया जाना चाहिए. जैसे, इंटरनल डेटाबेस या शेयर की गई सेटिंग.
हमले की एक संभावित स्थिति यह हो सकती है कि कोई नुकसान पहुंचाने वाली गैलरी या फ़ाइल पिकर बनाया जाए. जब कोई जोखिम भरा ऐप्लिकेशन इसका इस्तेमाल करेगा, तो वह नुकसान पहुंचाने वाला यूआरआई दिखाएगा.
इस तरह के हमले के कुछ वैरिएंट होते हैं:
- हमलावर के कंट्रोल में पूरी तरह से मौजूद
file://
यूआरआई, जो ऐप्लिकेशन की इंटरनल फ़ाइलों पर ले जाता है file://
यूआरआई का कुछ हिस्सा, हमलावर के कंट्रोल में होता है. इस वजह से, यह पाथ ट्रैवल के लिए ज़्यादा संवेदनशील होता हैfile://
ऐसा यूआरआई जो हमलावर के कंट्रोल वाले सिंबल लिंक (सिंबल लिंक) को टारगेट करता है. यह लिंक, ऐप्लिकेशन की इंटरनल फ़ाइलों पर ले जाता है- यह पिछले वैरिएंट की तरह ही है. हालांकि, यहां हमलावर बार-बार सिमलिंक टारगेट को किसी मान्य टारगेट से ऐप्लिकेशन की इंटरनल फ़ाइलों पर स्विच करता है. इसका मकसद, सुरक्षा जांच और फ़ाइल पाथ के इस्तेमाल के बीच की रेस कंडीशन का फ़ायदा उठाना है
असर
इस समस्या का इस्तेमाल करने से होने वाले असर में फ़र्क़ इस बात पर निर्भर करता है कि ContentResolver का इस्तेमाल किस काम के लिए किया जा रहा है. कई मामलों में, इसकी वजह से ऐप्लिकेशन का सुरक्षित डेटा बाहर निकाला जा सकता है या बिना अनुमति वाले पक्ष, सुरक्षित डेटा में बदलाव कर सकते हैं.
जोखिम कम करने के तरीके
इस जोखिम को कम करने के लिए, फ़ाइल डिस्क्रिप्टर की पुष्टि करने के लिए, नीचे दिए गए एल्गोरिदम का इस्तेमाल करें. पुष्टि हो जाने के बाद, फ़ाइल डिस्क्रिप्टर का इस्तेमाल सुरक्षित तरीके से किया जा सकता है.
Kotlin
fun isValidFile(ctx: Context, pfd: ParcelFileDescriptor, fileUri: Uri): Boolean {
// Canonicalize to resolve symlinks and path traversals.
val fdCanonical = File(fileUri.path!!).canonicalPath
val pfdStat: StructStat = Os.fstat(pfd.fileDescriptor)
// Lstat doesn't follow the symlink.
val canonicalFileStat: StructStat = Os.lstat(fdCanonical)
// Since we canonicalized (followed the links) the path already,
// the path shouldn't point to symlink unless it was changed in the
// meantime.
if (OsConstants.S_ISLNK(canonicalFileStat.st_mode)) {
return false
}
val sameFile =
pfdStat.st_dev == canonicalFileStat.st_dev &&
pfdStat.st_ino == canonicalFileStat.st_ino
if (!sameFile) {
return false
}
return !isBlockedPath(ctx, fdCanonical)
}
fun isBlockedPath(ctx: Context, fdCanonical: String): Boolean {
// Paths that should rarely be exposed
if (fdCanonical.startsWith("/proc/") ||
fdCanonical.startsWith("/data/misc/")) {
return true
}
// Implement logic to block desired directories. For example, specify
// the entire app data/ directory to block all access.
}
Java
boolean isValidFile(Context ctx, ParcelFileDescriptor pfd, Uri fileUri) {
// Canonicalize to resolve symlinks and path traversals
String fdCanonical = new File(fileUri.getPath()).getCanonicalPath();
StructStat pfdStat = Os.fstat(pfd.getFileDescriptor());
// Lstat doesn't follow the symlink.
StructStat canonicalFileStat = Os.lstat(fdCanonical);
// Since we canonicalized (followed the links) the path already,
// the path shouldn't point to symlink unless it was changed in the meantime
if (OsConstants.S_ISLNK(canonicalFileStat.st_mode)) {
return false;
}
boolean sameFile =
pfdStat.stDev == canonicalFileStat.stDev && pfdStat.stIno == canonicalFileStat.stIno;
if (!sameFile) {
return false;
}
return !isBlockedPath(ctx, fdCanonical);
}
boolean isBlockedPath(Context ctx, String fdCanonical) {
// Paths that should rarely be exposed
if (fdCanonical.startsWith("/proc/") || fdCanonical.startsWith("/data/misc/")) {
return true;
}
// Implement logic to block desired directories. For example, specify
// the entire app data/ directory to block all access.
}
खतरा: भरोसेमंद नहीं होने वाले content:// यूआरआई का इस्तेमाल करके गलत इस्तेमाल करना
content://
यूआरआई की कमजोरी का इस्तेमाल करके ContentResolver
का गलत इस्तेमाल तब होता है, जब हमलावर के कंट्रोल वाले यूआरआई को ContentResolver
एपीआई को भेजा जाता है, ताकि वह ऐसे कॉन्टेंट पर काम कर सके जिसे ऐक्सेस नहीं किया जाना चाहिए.
इस हमले के दो मुख्य तरीके हैं:
- ऐप्लिकेशन अपने अंदर मौजूद कॉन्टेंट पर काम करता है. उदाहरण के लिए: हमलावर से यूआरआई मिलने के बाद, मेल ऐप्लिकेशन बाहरी फ़ोटो के बजाय, अपने कॉन्टेंट प्रोवाइडर का डेटा अटैच करता है.
- यह ऐप्लिकेशन, प्रॉक्सी के तौर पर काम करता है. इसके बाद, यह हमलावर के लिए किसी दूसरे ऐप्लिकेशन का डेटा ऐक्सेस करता है. उदाहरण के लिए: मेल ऐप्लिकेशन, ऐप्लिकेशन X से ऐसा डेटा अटैच करता है जिसे किसी अनुमति से सुरक्षित किया गया है. आम तौर पर, हमलावर उस खास अटैचमेंट को नहीं देख सकता. यह उस ऐप्लिकेशन के लिए उपलब्ध होता है जो अटैचमेंट करता है, लेकिन शुरुआत में नहीं. इसलिए, यह कॉन्टेंट हमलावर को भेजा जाता है.
हमले की एक संभावित स्थिति यह है कि कोई नुकसान पहुंचाने वाली गैलरी या फ़ाइल पिकर बनाया जाए. जब कोई ऐप्लिकेशन इसका इस्तेमाल करता है, तो वह नुकसान पहुंचाने वाला यूआरआई दिखाता है.
असर
इस समस्या का इस्तेमाल करने से होने वाले असर में फ़र्क़ होता है. यह असर, ContentResolver के कॉन्टेक्स्ट पर निर्भर करता है. इसकी वजह से, ऐप्लिकेशन का सुरक्षित डेटा चुराया जा सकता है या बिना अनुमति वाले पक्ष, सुरक्षित डेटा में बदलाव कर सकते हैं.
जोखिम कम करने के तरीके
सामान्य सेटिंग
आने वाले यूआरआई की पुष्टि करना. उदाहरण के लिए, अनुमति देने वाली उन संस्थाओं की सूची का इस्तेमाल करना एक अच्छा तरीका माना जाता है जिनके पास आपके डेटा को ऐक्सेस करने की अनुमति है.
यूआरआई, ऐसे कॉन्टेंट प्रोवाइडर को टारगेट करता है जिसे एक्सपोर्ट नहीं किया गया है या जिसे अनुमति की मदद से सुरक्षित किया गया है. यह कॉन्टेंट प्रोवाइडर, असुरक्षित ऐप्लिकेशन से जुड़ा होता है
देखें कि यूआरआई आपके ऐप्लिकेशन को टारगेट करता है या नहीं:
Kotlin
fun belongsToCurrentApplication(ctx: Context, uri: Uri): Boolean {
val authority: String = uri.authority.toString()
val info: ProviderInfo =
ctx.packageManager.resolveContentProvider(authority, 0)!!
return ctx.packageName.equals(info.packageName)
}
Java
boolean belongsToCurrentApplication(Context ctx, Uri uri){
String authority = uri.getAuthority();
ProviderInfo info = ctx.getPackageManager().resolveContentProvider(authority, 0);
return ctx.getPackageName().equals(info.packageName);
}
इसके अलावा, अगर टारगेट की गई कंपनी को एक्सपोर्ट किया जाता है, तो:
Kotlin
fun isExported(ctx: Context, uri: Uri): Boolean {
val authority = uri.authority.toString()
val info: ProviderInfo =
ctx.packageManager.resolveContentProvider(authority, 0)!!
return info.exported
}
Java
boolean isExported(Context ctx, Uri uri){
String authority = uri.getAuthority();
ProviderInfo info = ctx.getPackageManager().resolveContentProvider(authority, 0);
return info.exported;
}
इसके अलावा, अगर यूआरआई को साफ़ तौर पर अनुमति दी गई है, तो यह जांच इस आधार पर की जाती है कि अगर डेटा को ऐक्सेस करने की साफ़ तौर पर अनुमति दी गई है, तो यूआरआई नुकसान पहुंचाने वाला नहीं है:
Kotlin
// grantFlag is one of: FLAG_GRANT_READ_URI_PERMISSION or FLAG_GRANT_WRITE_URI_PERMISSION
fun wasGrantedPermission(ctx: Context, uri: Uri?, grantFlag: Int): Boolean {
val pid: Int = Process.myPid()
val uid: Int = Process.myUid()
return ctx.checkUriPermission(uri, pid, uid, grantFlag) ==
PackageManager.PERMISSION_GRANTED
}
Java
// grantFlag is one of: FLAG_GRANT_READ_URI_PERMISSION or FLAG_GRANT_WRITE_URI_PERMISSION
boolean wasGrantedPermission(Context ctx, Uri uri, int grantFlag){
int pid = Process.myPid();
int uid = Process.myUid();
return ctx.checkUriPermission(uri, pid, uid, grantFlag) == PackageManager.PERMISSION_GRANTED;
}
यूआरआई, अनुमति से सुरक्षित ContentProvider को टारगेट करता है. यह ContentProvider, किसी ऐसे ऐप्लिकेशन का होता है जो जोखिम वाले ऐप्लिकेशन पर भरोसा करता है.
यह हमला इन स्थितियों में होता है:
- ऐप्लिकेशन के ऐसे नेटवर्क जहां ऐप्लिकेशन, पसंद के मुताबिक अनुमतियों या पुष्टि करने के अन्य तरीकों को तय करते हैं और उनका इस्तेमाल करते हैं.
- अनुमति के प्रॉक्सी हमले, जहां हमलावर किसी ऐसे ऐप्लिकेशन का गलत इस्तेमाल करता है जिसमें रनटाइम की अनुमति होती है. जैसे, READ_CONTACTS. ऐसा करके, वह सिस्टम की सेवा देने वाली कंपनी से डेटा हासिल करता है.
जांचें कि यूआरआई की अनुमति दी गई है या नहीं:
Kotlin
// grantFlag is one of: FLAG_GRANT_READ_URI_PERMISSION or FLAG_GRANT_WRITE_URI_PERMISSION
fun wasGrantedPermission(ctx: Context, uri: Uri?, grantFlag: Int): Boolean {
val pid: Int = Process.myPid()
val uid: Int = Process.myUid()
return ctx.checkUriPermission(uri, pid, uid, grantFlag) ==
PackageManager.PERMISSION_GRANTED
}
Java
// grantFlag is one of: FLAG_GRANT_READ_URI_PERMISSION or FLAG_GRANT_WRITE_URI_PERMISSION
boolean wasGrantedPermission(Context ctx, Uri uri, int grantFlag){
int pid = Process.myPid();
int uid = Process.myUid();
return ctx.checkUriPermission(uri, pid, uid, grantFlag) == PackageManager.PERMISSION_GRANTED;
}
अगर अन्य कॉन्टेंट प्रोवाइडर का इस्तेमाल करने के लिए अनुमति की ज़रूरत नहीं है, तो साफ़ तौर पर इन एजेंसियों के इस्तेमाल पर पाबंदी लगाएं. जैसे, जब ऐप्लिकेशन, अपने इकोसिस्टम के सभी ऐप्लिकेशन को सारा डेटा ऐक्सेस करने की अनुमति देता है.