安裝之前,APK 裡到底有什麼
APK 是一個附帶聲明的 zip 檔案。在 Android 執行它的任何一行程式碼之前,這個安裝包已經說明了它自稱是誰、支援哪些 Android 版本、想要哪些權限、哪些部分可以被其他應用呼叫,以及由誰簽章。這些都不需要安裝任何東西就能看到。先讀一遍,就能把一次盲目信任變成十分鐘的檢查——而這次檢查往往已經足夠做出決定。
為什麼側載的 APK 值得先看一眼
從官方商店安裝的應用有商品頁、評價記錄和發行者頁面。側載的 APK——從廠商網站、鏡像站、論壇貼文、聊天訊息或舊備份下載——沒有任何這樣的背景,而安裝提示也代替不了它。Android 安裝介面只顯示應用名稱和圖示,權限要到最後才出現,而且經過分組和簡化,恰好出現在你最不可能停下來思考的時刻。應用一旦安裝並啟動過一次,可能已經拿到了被授予的權限並用過網路。提問最便宜的時機是在此之前,趁檔案還只是一個檔案。
這並不是反對側載本身。廠商會直接散布正當應用,企業會用這種方式部署內部工具,舊版本有時也能解決真實問題。這裡反對的是不看就裝。用本站的 APK 分析器 在瀏覽器裡解析安裝包——檔案不會被上傳,也不會被執行——清單、權限、元件和簽章憑證會在一個檢視裡列出來。無論用什麼工具,都保持這個順序:先檢查,後安裝;一個經不起檢查的應用,本身就是答案。
清單是應用自己的聲明
每個 APK 都帶有 AndroidManifest.xml,以二進位 XML 儲存,它是應用對自己的聲明。它寫明套件名稱——Android 使用的唯一身分,例如 com.example.app——以及數字形式的 versionCode 和給人看的 versionName。它還宣告應用包含的元件、請求的權限,以及預期的硬體和軟體特性。由於 Android 會強制執行這份檔案的許多內容,它比商店頁面或下載頁更難隨手偽造:應用不能悄悄使用從未宣告的權限,也不能冒充一個套件名稱不同的應用的更新。
清單裡的兩個數字能說明不少維護狀況。minSdkVersion 是應用能執行的最老 Android 版本;下限很低,意味著要支援多年前的裝置和安全模型,有時是必要的,有時只是繼承下來忘了改。targetSdkVersion 是應用聲稱遵循的 Android 行為層級。Google 每年都會提高商店更新所要求的目標層級,因為更高的目標意味著應用接受更新的隱私和安全規則。一個側載應用如果目標層級落後好幾年,不一定是惡意的——但它在告訴你,它迴避了或從未滿足過那些新規則,你應該問為什麼。
權限要這樣讀
Android 把權限分類,類別比名稱更重要。一般權限在安裝時自動授予——存取網路就是熟悉的例子——因為系統認為它們風險低。危險權限涉及敏感資料和操作,如通訊錄、簡訊、精確位置、麥克風和相機,需要使用者可以拒絕的執行時彈窗。簽章權限只授予使用同一憑證簽章的應用或系統本身,因此第三方應用宣告它也得不到任何好處。讀權限清單時,先在心裡把它們分進這幾個類別,再去評判任何一行。
決定結論的是情境,而不是數量。手電筒要求讀取簡訊,沒有任何誠實的理由;簡訊應用要求同一權限,至少能解釋——讀取驗證碼,或者申請成為預設簡訊應用。銀行應用可能合理地請求許多權限,而一個簡單遊戲只請求幾個,卻可能恰好包含那個不合情境的。所以不要只按權限數量給應用打分。對每一個危險權限,問一句:這個應用的哪個功能沒有它就用不了?映射不到功能的請求就是發現的問題,也正是安裝時摘要會藏起來的東西。
匯出元件與它們帶來的攻擊面
應用由元件構成——活動(畫面)、服務、廣播接收器和內容提供者——清單會說明其中哪些是匯出的,也就是裝置上的其他應用可以存取。匯出元件本身不是錯誤:分享目標、檔案開啟方式和深連結,都是因為某個元件被有意匯出並加以保護,在現代 Android 中還需要明確宣告。風險在於那些本不該成為公共入口的匯出元件:任何應用都能啟動的服務、任何應用都能觸發的接收器,或是把應用資料交給任何來訪者、前面沒有任何權限檢查的提供者。
有兩個清單標誌值得在任何正式版應用裡直接查看。標記為可偵錯的應用可以被連接裝置上的工具附加和檢查;那是開發設定,把它帶進發行版,是一個關於建置方式的危險訊號。允許備份意味著應用的私有資料可以進入裝置備份,這可能很方便,也可能把你以為只留在應用內的資料移到一個遠不受控的地方。這兩個標誌都不能證明應用有害,但都很容易檢查、在成品中很難自圓其說,而且正是下載頁面上永遠不會出現的那類細節。
簽章憑證:Android 的身分體系
每個 APK 都經過簽章,簽章憑證是 Android 最接近身分證明的文件。只有當新舊兩個版本套件名稱相同且簽章者相同時,Android 才會把新版本作為更新安裝在已有應用之上。這條規則默默做了很多工作:陌生人無法為你已經信任的應用推送木馬化更新,因為他們沒有原始金鑰;而憑證指紋——通常以 SHA-256 摘要顯示——是核對連續性的實用方法。如果廠商公布了預期指紋,就拿來比對。本站的憑證與金鑰比對器更一般地涵蓋了憑證和金鑰的同一套指紋邏輯。
要清楚指紋能證明什麼、不能證明什麼。它證明這個檔案由持有某個私鑰的人簽署,並且與另一個由同一金鑰簽署的檔案相符或不符。它不能證明金鑰持有者誠實、稱職,甚至不能證明他就是憑證主體欄位裡寫的那家公司——那些欄位是簽署者自己填的。被重新打包的應用通常使用與原版不同的憑證簽署,所以指紋不符是強烈的停止訊號;指紋相符則只是連續性訊號。Android 裡的身分就是金鑰的連續性,僅此而已——請按這個標準對待它。
一份安裝前檢查清單
按固定順序把各部分拼起來,檢查只需幾分鐘。第一,身分:套件名稱是否與你預期的應用相符,版本代碼和版本名對這次要下載的發行是否合理?第二,維護:最低和目標 SDK 層級有多老,是否符合一個仍在維護的應用?第三,權限:列出危險權限,逐個映射到功能,遇到解釋不了的就停下來。第四,攻擊面:哪些元件被匯出,可偵錯和備份是否開啟?第五,簽章:憑證指紋是否與發行者公布的值相符,或至少與你已經信任的那個副本相符?把檔案放進 APK 分析器,在一個畫面上逐項過一遍這份清單。
然後分三檔做決定,而不是兩檔。一切都能映射到功能、指紋也核對無誤,就安裝。大部分相符但有一項需要觀察,就謹慎安裝——放在測試裝置、工作資料夾裡,或不授予有疑問的權限。套件名稱錯誤、指紋不符,或某個危險權限背後想不出任何功能,就放棄。放棄只損失一次下載;反方向可能損失一個帳號。也請保持分寸:這和封包擷取分析器的頭十分鐘一樣,是分診——在把一個檔案放進你隨身攜帶的裝置之前,快速而誠實地讀一遍它對自己的聲明。
常見問題
清單讀起來乾淨,就說明 APK 安全嗎?
不能。清單是一份聲明,不是一份行為報告。一個應用可以宣告一套看似克制而完全合理的權限和元件,卻仍然在程式碼裡做壞事——向外回連、濫用被合法授予的權限,或在安裝後下載新的行為。讀清單是分診:它能快速而廉價地發現身分不符、無法解釋的權限、暴露的元件和錯誤的簽章憑證。它不是惡意軟體結論,任何把清單讀取變成綠色「安全」印章的工具,都聲稱了證據不支持的東西。
為什麼同一個應用在不同工具裡顯示的權限不同?
通常有三個正當原因。第一,版本門控:權限可以帶有 maxSdkVersion,只適用於某個 Android 層級以下,不同工具對是否顯示被門控條目的處理不同。第二,分組:Android 在彈窗時按組展示權限,而清單列出的是單個權限,所以分組檢視比完整清單看起來短。第三,合併:打包進應用的程式庫會帶來自己的清單條目,建置時會被合併進最終檔案——所以安裝後的清單可能包含應用自身原始碼從未宣告過的權限。出現差異時應去看是哪一個原因,而不是自動當作竄改的證據。
不安裝任何東西就能檢查 APK 嗎?
可以——這正是瀏覽器本地分析器的意義。APK 作為檔案被解析:二進位清單被解碼,資源被讀取以取得標籤和字串,簽章憑證被提取並計算指紋。應用程式碼永遠不會被執行,任何裝置上都不會安裝東西;使用本站的分析器時,檔案也不會被上傳——解析發生在你的瀏覽器分頁裡。如果某個檢查服務要求你把 APK 上傳到伺服器,先問問自己:這個檔案——可能是一個內部建置——到底該不該出現在別人的機器上。