WARNING! 配置不當,或導致Kotlin原始碼洩漏!

Geedio發表於2018-01-11

自從去年Google扶正了Kotlin,使之成為了Android官方的推薦開發語言,Kotlin便迎來了春天。很多團隊/產品也紛紛加入了Kotlin的支援,大廠的應用也很多,社群對Kotlin也是讚不絕口。正在看此文的同學,也相信要麼用上Kotlin,要麼準備使用Kotlin。

這裡,筆者要給大家提個醒:舊專案引入Kotlin,如配置不當,會導致原始碼洩露!。這意味著我們所做的混淆、加固之類的防護操作都白費了!這可是相當嚴重的安全問題!

如圖。這是筆者在網上閒逛的時候,偶然發現的某應用包內竟然包含了Kotlin的原始檔!

WARNING! 配置不當,或導致Kotlin原始碼洩漏!

妥妥的如假包換的原始檔,程式碼、註釋都是全套的。

原因分析

當筆者發現這個情況的時候,內心暗喜:難道筆者不小心挖到了一個Kotlin的大新聞,只要使用了Kotlin,就會被開源?

筆者嘗試在本地復現這個場景,但遺憾的是,不管是新版本的Kotlin Plugin還是舊版本的Kotlin Plugin,打出來的包都不包含.kt檔案。隨後筆者又嘗試去應用寶抓取Top50的應用,發現使用了Kotlin的應用雖然多,但也沒出現圖上的應用一般的程式碼洩露情況。無法復現,還怎麼定位問題的原因?此時陷入了僵局。

後來,筆者檢視自家的應用時,發現自家應用引入了Kotlin後,也出現了這樣的問題。那這就不是小事了。

排查和定位過程按下不表,直觀的結果就是,打出來的APK包裡,混入了原始碼目錄下的.kt原始檔。

我們知道,打包過程中,有一個步驟叫做Jar包資源合併,這個步驟會把Jar包內資源合併到一起,打包到apk中。既然APK裡包含的.kt檔案,那極有可能是合併資源的任務出了問題。

可惜,比對了有問題的專案和正常的專案的build.gradle之後,無奈的發現,即便是同樣的GradleKotlin Pluginbuild tools版本,同樣的配置,依然無法在正常的專案下復現這個問題。

也就說,gradle的Jar包資源合併任務並不是導致問題的元凶。也是,Gradle如果有問題,社群也早就發現了。

但問題還是得解決,既然是資源被合併打包了,那就找方法做指定資源的排除唄。

這部分的工作是由java plugin乾的,那就到文件: The Java Plugin裡找答案。

首先看到這個任務:

WARNING! 配置不當,或導致Kotlin原始碼洩漏!

從描述可知,這個任務就是我們要找的,拷貝資源到jar包的資源目錄。

再往下看,專案的預設目錄結構:

WARNING! 配置不當,或導致Kotlin原始碼洩漏!

資源目錄是放置在src/main/resources,或對應的src/<程式碼集>/resources目錄內。

如果要自定義資源目錄的配置,看這個:

WARNING! 配置不當,或導致Kotlin原始碼洩漏!

也就是說,這個配置指定了程式碼集的資源目錄的位置。它會排除掉目錄內的.java檔案,其他的外掛,也可能從這裡移除掉額外的檔案型別。

看到這裡,大家也差不多明白了吧?

講道理,預設生成的專案的目錄結構中,資源目錄和程式碼目錄是區分開的。既然APK裡包含了.kt原始碼,那必然是資源目錄和程式碼目錄是同一個的情況。

由於java plugin預設會移除資源目錄內的.java檔案,因此,在以往的打包中,原始碼能夠被安全的移除掉,不至於導致洩露。

而現在,我們引入Kotlin的時候,會依舊保持原有的程式碼目錄結構,此時程式碼目錄中就混入的.kt檔案,由於不屬於資源剔除的範圍,自然就被當做資原始檔打包進APK裡了。

在出現了原始碼洩露的應用裡,我還發現了.aidl檔案,也就是IPC通訊時定義的介面檔案。這類檔案的洩露也是同樣的原因造成的。

至此,這個原始碼洩露案,也就告破了。

當然,說告破還有點早,畢竟上面給出的是推測,就算是真理,也是需要檢驗的。

回到自家工程的build.gradle裡一查:

android {
    sourceSets {
        main {
            manifest.srcFile 'AndroidManifest.xml'
            java.srcDirs = ['src']
            resources.srcDirs = ['src']
        }
    }
}
複製程式碼

果不其然,資原始檔所在的目錄和原始碼所在的目錄配置成了同一個。

至於出現這個問題原因,筆者反思了一下。這個專案屬於比較早期的專案,程式碼目錄結構遵循的是Eclipse時代的規範,後面擁抱變化轉Android Studio時,Gradle預設的那套專案佈局規範和Eclipse相差較大,為了避免對專案造成大的改動,所以採取了自定義目錄配置的做法,用較小的代價,完成了遷移。時過境遷,到了擁抱Kotlin變化的時候,就出問題了。

修復方案

明瞭問題的所在,定解決方案自然也就方便了:

  1. 方案一:直接移除resources.srcDirs = ['src']配置。
  2. 方案二:為資源目錄增加新的提出型別.kt
  3. 方案三:將資源目錄和程式碼目錄區分開來,不再混雜在一起。

這些方案裡,方案一有點簡單粗暴。對Android專案來說,影響倒還好,因為很多資源都是放在assets目錄裡,工程內很少會放這種資原始檔了。

方案二適用於那些資原始檔裡除了.kt檔案之外,還有別的資原始檔的情況,傳統java開發可能會有這種場景。

方案三是最穩妥,最合乎規範的推薦做法。將資源和程式碼分開,使得相關檔案在物理上保持了隔離,對整個專案來說,整體結構更加清晰。

對筆者這種情況,更好的方式是做一次專案結構的改造,使之符合Gradle的規範。

但歸根結底,這個問題屬於技術債務。很多時候,我們在開發的過程中,會為了貪圖方便,本著儘可能的減少影響面的想法,採取了一種折中的妥協的做法,度過了一時,但往往就埋下了禍根。

短期內沒時間,確實可以這麼做,但從長期來看,還是要把債務還上的。只是時間的問題罷了。

最後的最後

最後的最後,建議大家自查一下,避免出現和筆者統一的情況。尤其是那些從Eclipse時代轉過來的Android專案!

感謝閱讀到最後,希望本文對你有所幫助。如果覺得筆者的文章對你有所幫助,還請給個喜歡/感謝/贊。如有紕漏,也請不吝賜教。歡迎大家留言一起討論。:-)

後記

本文發出後,有朋友留言,指本文有標題黨的嫌疑。恕筆者無法苟同。誠然,如有些朋友所言,不就是自己一個配置錯了,關Kotlin什麼事情,Kotlin乃無辜躺槍。

但筆者認為,這固然不是程式語言的鍋,但卻是Kotlin工具鏈上的Kotlin Plugin沒兼顧到這種場景導致的安全漏洞。與之相對的Java Plugin對這種場景就處理得周到得多。

雖然最後筆者將問題的原因歸根於專案配置導致的問題,但筆者仍然認為,這種情況的發生,Kotlin Plugin也有一定的責任。完善的工具鏈,能為開發和使用帶來極大的便利,Kotlin Plugin也不例外。筆者在Kotlin接入的配置教程裡,看到很多人在宣揚Kotlin的引入很方便,方便的背後,卻可能會不小心帶來這麼大的安全隱患,筆者認為,是很有必要提醒使用了Kotlin的各位的。

另外,安全問題的產生,往往都是小細節上的失誤導致的,而失誤,往往來自於人。愛因斯坦這樣說道:“只有兩種事物是無窮盡的——宇宙和人類的愚蠢”。

能遇上這個問題的專案,基本都是從Eclipse時代過來的,這樣的專案,其具有的價值,料想是不言而喻的。筆者看到,有的同學認為,原始碼洩露就洩露,愛誰看誰看。個人認為,這是對專案的一種不負責任。

以上。

再更新

之前的標題《使用Kotlin或導致原始碼洩漏!》,評論指出有蹭熱度的嫌疑,參考了承香墨影的推送,改成《配置不當,或導致Kotlin原始碼洩漏!》,更直觀和開門見山。:-)

相關文章