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>權限),例如 provider permission、receiver permission、activity permission、service permission。 - 程式碼:在執行階段程式碼中註冊,例如
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,表示大多數應用程式可以要求並取得權限:
- 「normal」只需要宣告
- 「危險」會獲得許多使用者核准
因此,這些 protectionLevels 的安全性不高。
使用簽章權限 (Android >= 10)
盡可能使用簽章保護等級。使用這項功能可確保只有以與建立權限的應用程式相同的憑證簽署的其他應用程式,才能存取這些受保護的功能。請務必使用專屬 (非重複使用) 的簽署憑證,並將憑證安全地儲存在金鑰儲存區。
在資訊清單中定義自訂權限,如下所示:
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 權限和有趣的模糊測試發現項目