OWASP 類別:MASVS-CODE:程式碼品質
總覽
當自訂權限定義缺少或拼寫錯誤,或是資訊清單中濫用對應的 android:protectionLevel
屬性時,就會產生與自訂權限相關的風險。
舉例來說,惡意應用程式可以利用這些風險,建立同名的自訂權限,並套用不同的保護層級。
自訂權限可讓使用者與其他應用程式共用資源和功能。以下是合法使用自訂權限的例子:
- 控制兩個或多個應用程式之間的處理序間通訊 (IPC)
- 存取第三方服務
- 限制應用程式共用資料的存取權
影響
這項安全漏洞的影響是,惡意應用程式可能會取得原本應受保護的資源存取權。漏洞的影響取決於受保護的資源,以及原始應用程式服務的相關權限。
風險:自訂權限錯字
您可以在資訊清單中宣告自訂權限,但由於打字錯誤,因此使用其他自訂權限來保護匯出的 Android 元件。惡意應用程式可以利用應用程式輸入錯誤的權限,方法如下:
- 先註冊該權限
- 預測後續應用程式中的拼字
這可讓應用程式在未經授權的情況下存取資源或控制受害者應用程式。
舉例來說,有安全漏洞的應用程式想要使用權限 READ_CONTACTS
保護元件,但不小心將權限拼寫錯誤為 READ_CONACTS
。惡意應用程式可以聲明 READ_CONACTS
,因為它不屬於任何應用程式 (或系統),且可取得受保護元件的存取權。這個漏洞的另一個常見變種是 android:permission=True
。無論大小寫為何,true
和 false
等值都是權限宣告的無效輸入內容,處理方式也與其他自訂權限宣告錯字類似。如要修正這個問題,android:permission
屬性的值應變更為有效的權限字串。舉例來說,如果應用程式需要存取使用者的聯絡人,android:permission
屬性的值應為 android.permission.READ_CONTACTS
。
因應措施
Android Lint 檢查
宣告自訂權限時,請使用 Android Lint 檢查功能,找出程式碼中的潛在錯誤和其他潛在錯誤。
命名慣例
使用一致的命名慣例,讓拼寫錯誤更容易被發現。請仔細檢查應用程式資訊清單中的自訂權限宣告是否有錯字。
風險:孤立的權限
權限可用於保護應用程式的資源。應用程式可在兩個不同位置宣告存取資源所需的權限:
- AndroidManifest.xml:在 AndroidManifest.xml 檔案中預先定義 (如果未指定,系統會使用
<application>
權限),例如 提供者權限、接收器權限、活動權限、服務權限。 - 程式碼:在執行階段程式碼中註冊,例如:
registerReceiver()
。
不過,有時裝置上 APK 資訊清單中的對應 <permission>
標記並未定義這些權限。在這種情況下,這些權限稱為孤立權限。導致這種情況的原因有很多,例如:
- 資訊清單的更新和權限檢查的程式碼可能會有差異
- 建構作業可能未納入含有權限的 APK,或是納入錯誤版本
- 檢查或資訊清單中的權限名稱拼寫錯誤
惡意應用程式可能會定義並獲取孤立權限。如果發生這種情況,信任孤立權限來保護元件的特權應用程式就可能遭到入侵。
如果特權應用程式使用權限保護或限制任何元件,這可能會授予惡意應用程式該元件的存取權。例如啟動受權限保護的活動、存取內容供應器,或是向受孤立權限保護的廣播接收器進行廣播。
也可能產生以下情況:具有特殊權限的應用程式被誘騙具有特殊權限的應用程式,將惡意應用程式視為合法應用程式,因此能夠載入檔案或內容。
因應措施
請確認應用程式用於保護元件的所有自訂權限,也已在資訊清單中定義。
應用程式會使用自訂權限 my.app.provider.READ
和 my.app.provider.WRITE
,保護內容供應器的存取權:
Xml
<provider android:name="my.app.database.CommonContentProvider" android:readPermission="my.app.provider.READ" android:writePermission="my.app.provider.WRITE" android:exported="true" android:process=":myappservice" android:authorities="my.app.database.contentprovider"/>
應用程式也會定義及使用這些自訂權限,藉此防止其他惡意應用程式執行這類操作:
XML
<permission android:name="my.app.provider.READ"/>
<permission android:name="my.app.provider.WRITE"/>
<uses-permission android:name="my.app.provider.READ" />
<uses-permission android:name="my.app.provider.WRITE" />
風險:誤用 android:protectionLevel
此屬性說明權限中的潛在風險等級,指出系統在決定是否授予權限時,應遵循的程序。
因應措施
避免使用一般或危險防護等級
在權限中使用一般或危險 protectionLevel
,表示大多數應用程式都可以要求並取得權限:
- 「正常」只需要宣告
- 「dangerous」會獲得許多使用者的核准
因此,這些 protectionLevels
的安全性不高。
使用簽章權限 (Android 10 以上)
請盡可能使用特徵碼防護等級。採用這項功能可確保只有與建立權限的應用程式相同憑證簽署的其他應用程式,才能存取這些受保護的功能。請確保使用專屬 (未重複使用) 的簽署憑證,並安全地儲存在 KeyStore。
在資訊清單中定義自訂權限,如下所示:
Xml
<permission
android:name="my.custom.permission.MY_PERMISSION"
android:protectionLevel="signature"/>
限制只對已授予這項自訂權限的應用程式存取活動 (例如活動),如下所示:
Xml
<activity android:name=".MyActivity" android:permission="my.custom.permission.MY_PERMISSION"/>
任何其他應用程式只要使用與宣告此自訂權限的應用程式相同的憑證簽署,就會獲得 .MyActivity
活動的存取權,並需要在其資訊清單中宣告權限,如下所示:
Xml
<uses-permission android:name="my.custom.permission.MY_PERMISSION" />
小心簽章自訂權限 (Android 10 以下)
如果您的應用程式指定 Android 10 以下版本,那麼每當應用程式的自訂權限因解除安裝或更新而移除時,惡意應用程式就可能仍能使用這些自訂權限,進而規避檢查。這是因為權限提升安全漏洞 (CVE-2019-2200
) 已在 Android 10 中修正。
這也是為何我們建議使用簽名檢查 (而非自訂權限) 的原因之一 (此外,這也能降低競爭狀態的風險)。
風險:競爭狀況
如果合法應用程式 A
定義了其他 X
應用程式使用的簽章自訂權限,但後來遭到解除安裝,惡意應用程式 B
就可以使用不同的 protectionLevel
定義相同的自訂權限,例如 normal。這樣一來,B
就能存取 X
應用程式中受該自訂權限保護的所有元件,而不必使用與應用程式 A
相同的憑證簽署。
如果 B
在 A
之前安裝,也會發生同樣的情況。
因應措施
如果您希望元件只供使用與提供應用程式相同簽章的應用程式使用,您或許可以避免定義自訂權限來限制該元件的存取權。在這種情況下,您可以使用簽名檢查。當其中一個應用程式為另一個應用程式發出要求時,第二個應用程式可以先驗證兩個應用程式是否使用相同的憑證簽署,再發出該項要求。
資源
- 盡可能減少權限要求
- 權限總覽
- 防護等級說明
- CustomPermissionTypo Android Lint
- 如何使用 Android Lint
- 研究論文,深入說明 Android 權限和有趣的模糊測試結果