京東金融App收集隱私?屬開發錯誤,開源庫不背鍋
「大資料時代,人人都在“裸奔”」。本是一句玩笑話,無奈現實卻一次又一次地扯掉了遮擋在使用者隱私面前的遮羞布。
近日,京東金融 App 成為眾矢之的,原因是其被網友控訴,在使用者不知情的情況下,App 會獲取使用者截圖及照片,竊取隱私。而這究竟是怎麼一回事?
技術宅的發現
追溯事件本身,還得從一位技術愛好者、業餘開發者、微博博主@瘦出的肋骨已經消失的大俠阿木 釋出的一則微博提起。
昨天凌晨,該博主在微博上發視訊控訴,“京東金融 App 會獲取使用者的敏感圖並上傳。”
根據該博主釋出的視訊顯示,測試流程如下(僅在 Android 端):
-
開啟京東金融 App 後,退回到桌面,讓該 App 在後臺繼續執行;
-
開啟另一款招商銀行 App,對該 App 任意頁面進行截圖;
-
隨後開啟手機中檔案管理器,找到京東金融的檔案目錄,開啟快取檔案後,竟然發現了此前對招商銀行 App 頁面的截圖(android/data/com.jd.jrapp/cache/uil-images)。
緊接著在 20 分鐘後,@瘦出的肋骨已經消失的大俠阿木 再次發微博視訊表示,“京東金融 App 不止偷截圖,還會偷照片”。在此次視訊演示中,他同樣先打開了京東金融 App,隨後開啟美顏相機,並使用美顏相機拍攝一張照片儲存,如其預料的一樣,在上述京東金融 App 的快取目錄下也找到了剛剛攝下照片。
此訊息一經爆出,立即引發部分京東金融 App 使用者恐慌,甚至也有不少使用者稱:“復現成功。”對此,在評論區,網友們也展開激烈討論:
-
應該是給給了訪問相簿的許可權吧,禁掉許可權應該就拿不到圖了;
-
不止京東,國內很多 App 都會把使用者隱私按在地上摩擦;
-
先要確認是不是官方 App 的行為,這個要等官方解答,但作為一個安全從業者,Android 生態上的 App 分發平臺及 App 自身的許可權管控安全問題確實亟需關注,截圖、麥克風、攝像頭許可權都是重災區。
事實上,針對該事件,存在一個最為爭議的問題就是,該博主表示的“獲取使用者的敏感圖片並 上傳 ”問題。倘若在未經明確告知使用者的前提下,將獲得的圖片上傳至京東的伺服器端,那麼該 App 竊取使用者隱私幾近實錘了。所以京東金融 App 所獲取的使用者截圖及照片,究竟是儲存在了使用者個人手機的本地端?還是上傳到了伺服器端?
技術宅的深挖
基於這一問題,一位軟體開發者、知乎作者 @琴梨梨(https://zhuanlan.zhihu.com/p/56875556,已獲作者授權 ) 通過反編譯程式碼,對此事件進行了一波簡要分析:
以下為解析正文(在不改變原意的基礎上,對文字稍做修改):
根據微博網友@瘦出的肋骨已經消失的大俠阿木 爆料的視訊中,我們可以看到一個名為 uil-images 的資料夾,接下來,直接進 dex 挖字串:
從中,我們發現其全部來自一位暱稱為 nostra13 的開發者的開源庫。順藤摸瓜,再去 GitHub 上搜索詳情:
該開源專案獲得的 Star 還挺多多嘛,按照道理不應該是開源庫的鍋啊。
接著爬呼叫開源庫的類並過濾關鍵詞 screenshot 找到了京東金融 App 捕獲截圖功能程式碼的這個位置:Lcom/jd/jrapp/bm/common/screenshot/
從中可以看到一個接收器。接下來,拿著這個接收器倒爬,發現在 activity 基礎類裡註冊了接收器。
其中包括一個 startlisten 方法,再次返回去找這個方法:
這個方法很簡短,但裡面這個 businessshot 為什麼要帶個 business 字樣呢?有點耐人尋味。
接著去找這個方法:
就一個 iput。因為 iput 要求附加 context,所以肯定存在 iget 且僅存在於這個類裡(包括附屬類)。
在這個類裡搜尋變數,發現只有 onShot 方法裡有:
但是按照道理這個方法應該是截圖後去呼叫的,前面這個註冊接收器怎麼註冊的還是有點迷。
返回基礎 activity 類翻,發現這個:
invoke-virtual {v0, v1}, Lcom/jd/jrapp/bm/common/screenshot/ScreenShotListenManager;->setListener(Lcom/jd/jrapp/bm/common/screenshot/ScreenShotListenManager$OnScreenShotListener;)V
看樣子這個 manager 類裡有問題。
後來發現一個新變數,接著去爬這個變數:
然後發現這個 manager 裡還真有點東西:
出現在方法 handleMediaRowData 裡。再深度探究這個方法,發現又在 handleMediaContentChange 這個方法裡。繼續往下,發現這個 access 方法:
其中這個方法的 p1 是個 uri。到這裡,感覺已經快接近真相了。
果真,在一個附屬類裡找到了這個 access 的引用:
類名 ScreenShotListenManager$MediaContentObserver,似乎是監控媒體變化。
編譯這個監聽器,找 init:
找到了 init,在 startListen 方法裡。
至此為止,listener 部分分析結束。
接下來要做的是分析這個接收器到底呼叫開源庫做了什麼。關鍵程式碼在:
sget-object v2, Lcom/jd/jrapp/library/imageloader/ImageOptions;->commonOption:Lcom/nostra13/universalimageloader/core/DisplayImageOptions;
invoke-virtual {v1, p1, v0, v2}, Lcom/jd/jrapp/library/imageloader/JDImageLoader;->displayFile(Ljava/lang/String;Landroid/widget/ImageView;Lcom/nostra13/universalimageloader/core/DisplayImageOptions;)V
這個 displayFile 方法有點蹊蹺。
追根溯源,我們發現在 JDImageLoader 裡面呼叫的這個方法如下
.method public displayFile(Ljava/lang/String;Landroid/widget/ImageView;Lcom/nostra13/universalimageloader/core/DisplayImageOptions;)V.registers 6.prologuenew-instance v0, Ljava/lang/StringBuilder;invoke-direct {v0}, Ljava/lang/StringBuilder;->()Vconst-string/jumbo v1, "file://"invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;move-result-object v0invoke-virtual {v0, p1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;move-result-object v0invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;move-result-object v0//截止到現在都是在獲取uriinvoke-virtual {p0, v0, p2, p3}, Lcom/jd/jrapp/library/imageloader/JDImageLoader;->displayLocalImage(Ljava/lang/String;Landroid/widget/ImageView;Lcom/nostra13/universalimageloader/core/DisplayImageOptions;)V//用開源庫展示return-void
.end method
似乎截止到現在,我們也並沒有發現 App 的操作出現攻擊性程式碼,看方法名判斷是僅僅獲取截圖並顯示。
但是顯示之後為什麼檔案就跑京東金融 App 私有目錄裡去了?
初步判斷和開源庫脫不開關係。
於是,繼續往下研究,當看到 displayLocalImage 這個方法,我們去找找:
從中,我們發現呼叫了另外一個 displayLocalImage 方法。
對此,筆者不禁強烈譴責這種俄羅斯套娃式寫法,點名批評!!!
接著我們開啟這個套娃看看:
其中,呼叫了開源庫 displayImage 方法。
精確定位,發現又是個套娃:
看來,這套娃還不止一層:
有點意思,接著挖掘。
這會是一個極長的方法,應該對了:
方法有點長,複製到一個新 smali 裡看看。
為了加快分析我們把出現關鍵資料夾名稱的兩個類 StorageUtils 和 DefaultConfigurationFactory 放進去搜索,可以得到這個:
初步推斷是用私有目錄做快取。
我們來看看這個方法 createDiskCache:
.method public static createDiskCache(Landroid/content/Context;Lcom/nostra13/universalimageloader/cache/disc/naming/FileNameGenerator;JI)Lcom/nostra13/universalimageloader/cache/disc/DiskCache;.registers 13invoke-static {p0}, Lcom/nostra13/universalimageloader/core/DefaultConfigurationFactory;->createReserveDiskCacheDir(Landroid/content/Context;)Ljava/io/File;move-result-object v2//建立快取路徑,正是uil-images路徑出現的原因const-wide/16 v0, 0x0cmp-long v0, p2, v0if-gtz v0, :cond_cif-lez p4, :cond_1d.line 83:cond_cinvoke-static {p0}, Lcom/nostra13/universalimageloader/utils/StorageUtils;->getIndividualCacheDirectory(Landroid/content/Context;)Ljava/io/File;move-result-object v1//獲取路徑準備寫入:try_start_10new-instance v0, Lcom/nostra13/universalimageloader/cache/disc/impl/ext/LruDiscCache;move-object v3, p1move-wide v4, p2move v6, p4invoke-direct/range {v0 .. v6}, Lcom/nostra13/universalimageloader/cache/disc/impl/ext/LruDiscCache;->(Ljava/io/File;Ljava/io/File;Lcom/nostra13/universalimageloader/cache/disc/naming/FileNameGenerator;JI)V:try_end_18.catch Ljava/io/IOException; {:try_start_10 .. :try_end_18} :catch_19//初始化快取模組:goto_18return-object v0.line 87:catch_19move-exception v0.line 88invoke-static {v0}, Lcom/nostra13/universalimageloader/utils/L;->e(Ljava/lang/Throwable;)V//異常處理:cond_1dinvoke-static {p0}, Lcom/nostra13/universalimageloader/utils/StorageUtils;->getCacheDirectory(Landroid/content/Context;)Ljava/io/File;move-result-object v1//獲取快取路徑準備寫入new-instance v0, Lcom/nostra13/universalimageloader/cache/disc/impl/UnlimitedDiscCache;invoke-direct {v0, v1, v2, p1}, Lcom/nostra13/universalimageloader/cache/disc/impl/UnlimitedDiscCache;->(Ljava/io/File;Ljava/io/File;Lcom/nostra13/universalimageloader/cache/disc/naming/FileNameGenerator;)V//初始化快取限制模組goto :goto_18
.end method
至此為止,結論出來了。
這個開源庫用私有目錄作為快取目錄,把展示的圖片儲存在快取目錄下(雖然我不認為這樣可以加速載入)。
然後京東金融 App 顯示截圖的時候呼叫了開源庫,截圖就出現在私有目錄下了。
並沒有惡意程式碼,挺正常的對吧?
但真的正常嗎?京東金融 App 為何要顯示使用者的截圖?
對於這個問題,開源庫作者顯然不能背鍋。還請京東金融 App 程式設計師站出來,指使程式設計師做出這種 feature 的產品經理也難咎其責。
京東金融迴應:絕對不會收集未經使用者授權的任何資訊,更不會竊取!
從上我們可以看出,在經過知乎作者@琴梨梨(https://zhuanlan.zhihu.com/p/56875556)一輪程式碼反編譯之後,確實並有沒發現京東金融 App 上傳使用者截圖及照片至伺服器端的程式碼,那為何其又要收集使用者的截圖及照片,並將其儲存至 App 的私有目錄下?
對此,京東金融客服於昨天下午釋出宣告表示,之所以會有圖片快取,是因為和此前京東金融 App 中上線的一個名為“圖片助手”的便利小功能有關。
此外,其還表示,快取圖片只儲存在使用者本地手機裝置內, 不會上傳到京東金融後臺。 目前,京東金融 App 已暫時下線“圖片助手”小功能,待進一步改進使用者安全體驗後再上線。
風口浪尖的京東金融
然而對著這樣一則迴應宣告,不少網友們並不買賬。主要原因有二。
其一:原爆料微博博主@瘦出的肋骨已經消失的大俠阿木 使用的是 Android 手機進行測試,而京東金融給出的迴應宣告中卻是 iPhone 手機測試截圖。雖然在完了兩個小時之後,京東金融客服聲稱:“小編剛才一著急,拿自己的蘋果手機就截了。這是同事安卓手機的截圖。”
但通過對比,有網友表示,原宣告中蘋果手機的截圖是 12:07,2個小時之後,補的安卓手機測試截圖是 12:04,難道是穿越了?
對於這個問題,如果是京東金融工程師同時用 Android 和 iPhone 對 App 進行了測試,最終運營人員用錯了圖片,這倒是也可以理解。
但是對於整個宣告中,京東金融官方隻字未提其 App 私有目錄獲取照片一事,不少使用者也頗為不解。
對此,就在剛剛,京東金融再次發微博表示,Android 系統上京東金融 App 5.0.5 之後的版本存在上述問題,當前已下線修復。此外會於下週一即明天邀請權威官方機構對京東金融 App 進行全面安全性檢測,邀請包括@瘦出的肋骨已經消失的大俠阿木 在內的使用者和外部專家、媒體組成資訊保安顧問小組,對其服務進行監督。
道不清的使用者隱私,需要時刻警惕的是我們自己
本想為使用者提供更為便捷的服務,萬萬沒想到成為了疑似竊取隱私的元凶。事實上,對於任何一款產品,提出質疑未必不是一件好事,畢竟提出問題才會有反思與改進。
其實,這樣的類似事件也並非第一次出現。去年,Facebook 深陷“資料洩露門”之中、QQ 瀏覽器涉嫌私自調動攝像頭、百度手機輸入法被指擅自呼叫錄音許可權、WiFi 萬能鑰匙被爆竊取 9 億使用者隱私,甚至於幾天前,深圳一家 AI 公司被爆出,人臉資料遭到洩露,導致 256 萬用戶敏感資料慘遭“裸奔”。
如今隨著《網路安全法》的日益完善,雖然現狀已經有了良好的改善,但是如果使用者自身不時刻保持警惕,或許隨手點選的一個“同意”,洩露的可能就是自己全部的家底。
參考來源:
-
https://zhuanlan.zhihu.com/p/56875556;
-
https://zhuanlan.zhihu.com/p/56877625,作者:@琴梨梨,本文已獲授權,如需轉載,請聯絡原作者。
宣告:本文來自CSDN,版權歸作者所有。文章內容僅代表作者獨立觀點,不代表安全內參立場,轉載目的在於傳遞更多資訊。如需轉載,請聯絡原作者獲取授權。