政府新推出的「安心出行」App,由 react native 寫成,因此Android App 內主要的運作是在 Javascript 中進行,Java 的部份主要為 react native 本身及所使用 library 的 “native” module ,如背景下載,相機操作,網絡等介面。
Android 版本似乎再細分為 Google Play 及華為版本,以下所述的是根據從第三方下載的 Google Play 版本。
結構
如上文所述,程式主體以 Javascript 編成,已經過 uglify 成為一個大 Javascript 檔,放於 asset/index.android.bundle
內。該 bundle 有超過 1200 行,當中 module 名稱及大部份 function 及 variable 名已被縮為一個字元,每行大概對應一個 Javascript Module。
要查看內容,要先用 js-beautify
回復為較正常的縮排格式,大約有 110k 行。
未能搜尋
「安心出行」在 Google Play 的評語,最多的問題竟然是(上架頭一日)未能搜尋到此 App,要知索引更新其實是 Google Play 的問題,不料帶來政府故作神秘的指責。
GET_TASKS 權限問題
較引起關注的是 android.permission.GET_TASKS
,在 Google Play 的描述為 retrieve running apps,在 Android 5 以前是可以藉 getRecentTasks
及 getRunningTasks
,偵察其他 App 的執行情況,亦即可監視用戶活動,但其後(API 21) Google 已大幅限制非系統 App 可看其他 App 的資訊,非系統 App 僅可以偵察自已 App 其他 Component 的情況。
因此除非你使用 Android 5 以前的系統,否則基本上此權限沒有監視其他活動的能力。(利申,「小鴨幹線」(最低要求仍為 Android 2.2)有要求 GET_TASKS
權限,在舊機種偵察電話進程是否在前景、「小熊來電」亦有同一權限)。
那麼「安心出行」(最低要求 Android 4.1) 使用 GET_TASKS
權限做什麼呢,原來是由於這個 react native App 用了 react-native-background-fetch 這個 react native 函式庫(library)來在背景下載資料,而 GET_TASKS
權限是這個 library 的要求(在編繹時所有 library 的權限要求會合併,變為 App 的權限)。使用權限的原因,是在背景下載時偵測本身的前景 App 是否在執行,若是的話,可以與前景 App 溝通。見 BackgroundFetch.java
第271行。
在「安心出行」中似乎此處為唯一可能使用此權限的地方,因此,即使 Android 5 以下,亦未有證據構成問題。
事實上,去年已有該 library 用戶建議,移除 library 對 GET_TASKS
權限的依靠,改以其他方式偵測前景 App ,以免引起私隱誤會,見此 Github issue,不過作者對建議似乎有保留。
不過,open source 的其中一項好處,是源碼可以自行修訂的。政府若要回應關注,將該 library fork 出來再作輕微修訂,便可在更新「安心出行」時移除該權限,符合最低權限的聲稱。事實上,同一程序不同模組間的溝通有大量替代方案,如 broadcast 機制、event bus、RxJava 等。
有否收集過量資料?
回到 Javascript 部份,似乎除了 Google Firebase 推送,網絡只定義了以下接口:
下載:
CONFIG
: 下載組態檔,該檔定義某些參數,如不同種類的接觸(目前為預設及的士)的資料保留日期(目前為 31 日),配對定義(14日內),check out 提示時間(1小時),以及下載新版的通知。
GET_BATCH_FILES
: 下載感染個案的資料檔目錄 (JSON)
DOWNLOAD_KEYS
: 下載感染個案的詳細到訪資料(ZIP Protobuf 格式)
取得其他供顯示的 WEB 內容,如網頁,私隱政策等。
上載:
OCR
:上載的士車牌圖檔供 OCR 文字辨識,只上載圖像檔
VERIFY_PIN
: 供確診者上載由政府提供的一次性密碼,加上隨機 UUID 以作確認,供之後上載電話內的詳細到訪資料
UPLOAD_KEYS
: VERIFY_PIN
確認後實際上載確診者到訪資料,由於有密碼確認,可防止有人惡意上載假資料。
似乎在確診者以外,並未發現有特別的收集資料情況,如各類手機辨識碼等,(不過注意若有意隱藏,只靠正常看部份程式碼難以排除任何可能性)。
不過要注意,OCR 文字辨識部份,所攝的圖像是會上傳到政府伺服器以作辨認,代碼類似下圖:
RNFetchBlob.fetch('POST', Url.OCR, { 'Content-Type': 'multipart/form-data' }, [ { name: 'file', filename: filename, uri: uri, type:'image/' + filetype, data: base64} ] );
雖然沒有特別傳送任何額外資料,但流動網絡 IP,手機 agent string (包括機型等)仍會連同車牌資料上傳(伺服器會提供辨認後的車牌),一般亦會紀錄在 log 內。
事實上大部份手機有足夠能力,在離線時自行進行 OCR 運算(尤其這裏只涉及統一格式的英數字),若可以離線 OCR ,可較全面地免除顧慮,更符合資料保存於手機內,不會上傳中央資料庫的說法。
下回會看看資料的儲存及所謂加密。