移動應用安全開發指南(Android)--完結篇(http://www.bubuko.com/infodetail-577312.html)

一、認證和受權

概述android

 

 

認證是用來證實用戶身份合法性的過程,受權是用來證實用戶能夠合法地作哪些事的過程,這兩個過程通常是在服務器端執行的,但也有的APP出於性能提高或用戶體驗等緣由,將其作在客戶端完成,由此致使客戶端繞過等問題。web

安全準則算法

 

 

  1. 在客戶端作認證和受權是很難保證安全的,因此應該把認證和受權作在服務器端。若是確實有特殊的需求,能夠和安全工程師進行溝通作單一case分析。
  2. 儘量避免在設備上存儲用戶名和密碼,可使用登陸認證後得到的token進行鑑權(同時注意控制token的有效期)。

詳細描述安全

 

 

Item B的典型應用場景是實現自動登陸,用戶登陸認證後在本地存儲用戶的認證token,用戶退出程序時認證token不會被刪除,再次打開程序時可直接攜帶認證token獲取數據,同時爲了保證了足夠的安全性,能夠根據當前終端硬件信息產生獨立密鑰,而後對token進行加密。具體設計參考附錄8。服務器

備註web安全

 

 

在本地存儲對稱加密後的用戶口令密文,在登陸時還原出明文也是實現自動登陸的一種可選方案,但其安全性偏低,故在當今已並不是一種主流的作法。性能

     

二、加密解密

概述this

 

 

開發人員在移動應用中一般會對敏感數據進行加密處理,可是使用不當有可能讓其保護強度削弱,甚至大打折扣,所以,正確的選擇加解密算法顯得很是重要。編碼

安全準則加密

 

 

  1. 在不須要還原用戶明文密碼的場景使用哈希算法,在須要還原用戶明文密碼的場景下使用對稱加密算法,而且始終優先選擇使用哈希算法。
  2. 使用目前主流的安全加密算法,好比哈希算法可使用sha256,對稱加密算法可使用AES128/256,不使用過期的不安全算法,好比RC四、RC五、MD5和SHA1。
  3. 不使用自定義的加密算法。
  4. 密文和密鑰不要放在同一文件或同一目錄內,應分開存放。
  5. 密鑰不可硬編碼在代碼裏面。

詳細描述

 

 

使用AES128加密算法時,密鑰應同時知足長度(128bit)和複雜度的要求,建議使用安全的隨機數發生器產生安全的密鑰,Sha256哈希算法和AES128對稱加密算法的使用方法請參考附錄1。

備註

 

 

注意:在某些不牽涉敏感數據的場景下,不安全的哈希算法仍然是可用的,好比用於校驗文件或數據的完整性。

     

 

 

 

三、安全配置和部署

概述

 

 

安全開發能夠大大下降移動應用的安全風險,一樣地,安全的配置和部署可讓風險降到最低。

安全準則

 

 

  1. 確保使用的第三方組件是從官方下載的,而且是最新版本的。
  2. 爲應用程序申請最小的Permissions,若是用不上就不要申請。
  3. 應用和補丁在發佈前建議進行病毒和惡意代碼檢測。
  4. 爲敏感數據輸入界面提供防截屏措施,對抗木馬。

詳細描述

 

 

在Activity的onCreate()方法的初始化部分加入如下代碼可用於防截屏:

getWindow().addFlags(WindowManager.LayoutParams. FLAG_SECURE);

備註

 

 

非官方的庫可能被植入惡意代碼,而使用最新版本的庫(非beta版)能夠下降漏洞存在的可能性。

     

 

 

 

四、應用加固

概述

 

 

一般一個應用發佈後可能會面臨如下風險:

A.  應用被別人解包植入廣告或惡意代碼再重打包發佈。

B.  應用被暴力破解。

C.  應用的核心關鍵代碼邏輯被逆向。

所以,有必要在技術層面採起必定的緩解措施。

安全準則

 

 

  1. 對Java代碼進行混淆,對抗反編譯。
  2. 對Native代碼進行加殼,對抗反彙編。
  3. 應用程序加入動態反調試方法。
  4. 應用程序加入防二次打包的方法。

詳細描述

 

 

  1. 可使用proguard對Java源碼進行混淆。
  2. 可使用UPX進行加殼保護,請參考《Android SO加殼指南v1.0》。

 

  1. 預先在AndroidManifest.xml文件插入android:debuggable=」false」,在程序中判斷該標誌位是否被篡改,此外,android SDK也提供了相關方法來檢測調試器是否已鏈接,可在程序中隨機插入檢測,關鍵代碼以下(詳情參考附錄10):
  2. 應用程序被篡改並重打包時一定要從新簽名,簽名值和原開發者的一定不同(不考慮證書丟失的狀況),另外,從新編譯程序classes.dex文件確定會變,所以可在程序運行時對比簽名或CRC值的方法對抗重打包(參考附錄11)。

備註

 

 

以上方案參考《Android軟件安全與逆向分析》一書,但只能提供比較基本的保護措施,若是要進一步提升攻擊者的攻擊門檻,建議使用第三方的定製方案。

     

 

 

 

五、MISC(其它)

概述

 

 

本項做爲其它移動客戶端項的進一步補充。

安全準則

 

 

  1. 關鍵性業務邏輯代碼應放在native代碼實現,除此之外,儘可能使用android SDK作開發,減小對native代碼的依賴(native代碼通常採用C/C++編寫,容易出現緩衝區溢出等漏洞)。
  2. 儘可能少用動態加載的方式執行代碼(好比使用DexClassLoader),若是須要從外部存儲動態加載可執行文件或類文件(好比使用DexClassLoader),應通過嚴格的文件完整性驗證。

詳細描述

 

 

文件完整性校驗方案(參考附錄9):

  1. 對待動態加載的可執行文件或類文件進行哈希計算,並與存儲在服務器端的正確的哈希值進行對比,若是一致則表示文件未被篡改過,不然拒絕執行加載。

備註

 

 

存放在外部存儲的文件是可公共訪問的,可能會被其它惡意進程篡改,動態加載這些文件就有可能致使惡意代碼執行。

     

 

 

 

六、服務器端的安全

概述

 

 

大部分移動應用並不是一個獨立的單機程序,須要在服務器的支撐下完成一系列的功能,而服務器通常是以web API、web service等方式爲移動客戶端提供服務,所以,也一樣存在web應用的安全問題,而這部分問題牽涉面廣而複雜,沒法在單獨的item內進行描述,可參考《web安全開發指南》

安全準則

 

 

請參考《web安全開發指南》

詳細描述

 

 

 

備註

 

 

 

 

 

 

十、Android動態反調試方案:

10.一、檢測AndroidManifest.xml的調試標誌位是否被篡改:

if((getApplicationInfo().flags &= ApplicationInfo.FLAG_DEBUGGABLE) != 0){

System.exit(1);//使程序強制退出

}

注意:使用此方法時必須預先在AndroidManifest.xml設置android:debuggable=」false」,攻擊者要嘗試調試應用時頗有可能去修改該參數,於是此手法可用於作動態反調試檢測。

10.二、檢測應用程序是否鏈接調試器:

if(android.os.Debug.isDebuggerConnected()){

System.exit(1);

}

十一、防止二次打包方案:

11.一、簽名檢查

public class getSign {

public static int getSignature(PackageManager pm , String packageName){

PackageInfo pi = null;

int sig = 0;

Signature[]s = null;

try{

pi = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);

s = pi.signatures;

sig = s[0].hashCode();//s[0]是簽名證書的公鑰,此處獲取hashcode方便對比

}catch(Exception e){

handleException();

}

return sig;

}

}

主程序代碼參考:

pm = this.getPackageManager();

int s = getSign.getSignature(pm, "com.hik.getsinature");

if(s != ORIGNAL_SGIN_HASHCODE){//對比當前和預埋簽名的hashcode是否一致

System.exit(1);//不一致則強制程序退出

}

11.二、CRC校驗保護

private boolean checkcrc(){

boolean checkResult = false;

long crc = Long.parseLong(getString(R.string.crc));//獲取字符資源中預埋的crc

ZipFile zf;

try{

String path = getApplicationContext().getPackageCodePath();//獲取apk安裝路徑

zf = new ZipFile(path);//將apk封裝成zip對象

ZipEntry ze = zf.getEntry("classes.dex");//獲取apk中的classes.dex

long CurrentCRC = ze.getCrc();//計算當前應用classes.dex的crc

if(CurrentCRC != crc){//crc值對比

checkResult = true;

}

}catch(IOException e){

handleError();

checkResult = false;

}

return checkResult;

}

注意:一旦修改源代碼,從新編譯後classes.dex的CRC值就會變掉,所以正確的CRC值置不可以預置在代碼中,能夠考慮置放在資源文件中。

相關文章
相關標籤/搜索