1. 程式人生 > >安卓開發,關於程式碼安全的注意點,平常開發中你有沒有注意!!!

安卓開發,關於程式碼安全的注意點,平常開發中你有沒有注意!!!

發揚分享精神,做一個快樂的開發者!

看CSDN有好長時間了,感謝那些善於分享的開發者,感謝你們 ,閱讀你們的文章,我感覺有很快的進步,我一直也想寫部落格,把自己的見解和大家分享,只是苦於不知道寫些什麼,現在機會來了,我要把我研究的一些關於程式碼安全的試題給大家分享一下,其中參考了很多的網上資源,也有很多自己的理解,可能會有一些偏差,希望大家能夠指正.

1,關於安卓的剪下板風險.
手機裡面的幾乎所有的程式都能訪問剪下板,甚至一些許可權不高的APP都可以通過剪貼簿功能獲取我們複製或者剪下的資訊。如果我們複製或者剪下賬戶密碼資訊,很容易就被嗅探洩密,原因是Android剪貼簿的內容向任何許可權的app開放 .如果是明文內容將會有資訊洩露的風險,

首先可能有的人不是很熟悉,安卓的剪下板,我在先說一下安卓剪下板的用法.

1,先獲取一個Manger的物件,和獲取大多管理服務一樣,在上下文的環境中呼叫 getSystemService(CLIPBOARD_SERVICE);獲取一個剪下板管理器物件 取名為manager ,強轉成ClipboardManager;

2.現在有一個管理器物件了,還有有一個存放剪下的內容的地方就是ClipData,這個物件不是new出來的而是通過靜態方法ClipData.newPlainText(CharSequence label, CharSequence text),
ClipData.newIntent(CharSequence label, Intent intent),
ClipData.newUri(ContentResolver resolver, CharSequence label,
Uri uri) 獲得的,分別對應儲存的三種類型的資料: 文字,Intent,URL.
這裡我以複製密碼為例 :

// 剪下板資料
        ClipData clip = ClipData.newPlainText("password", "helloworld123456");

3.現在剪下板管理物件有了,資料物件也有了,就把資料通過manager放進剪下板裡面.

manager.setPrimaryClip(clip);

現在剪下板就使用完成了,這裡我模擬複製了密碼,現在剪下板裡面的內容可以別任意APP讀取,可想而知,這裡應該是程式碼安全的注意點.

現在我們看一下如何讀取剪下板的資料
如下程式碼可以在任意APP中讀取剪下板的文字內容:

ClipboardManager cm = (ClipboardManager)getSystemService(CLIPBOARD_SERVICE);
ClipData cd2 = cm.getPrimaryClip(); str2 = cd2.getItemAt(0).getText().toString();

修改方法:
使用完clipboard及時清空,並避免使用剪貼簿明文儲存敏感資訊
我找了API但是沒有找到清空的方法,這裡我們可以這樣給他清空

ClipData data = ClipData.newPlainText("password", "");
        manager.setPrimaryClip(data);

一句話 : 使用安卓剪下板的時候注意清空,並避免使用剪貼簿明文儲存敏感資訊!!!!

2. 關於安卓隨機數風險

安卓使用SecureRandom程式碼。

    SecureRandom secureRandom = new SecureRandom();

        byte[] b = new byte[] { (byte) 1 };
        //種子一樣 每次生成的隨機數是一樣的  設定了自己的種子 代替的系統的種子
        secureRandom.setSeed(b);
        // Prior to Android 4.2, the next line would always return the same
        // number!
        for (int i = 0; i < 30; i++) {

            System.out.println(secureRandom.nextInt());
        }

java中還有一個 Random 類 基本類似.

解析:
在Android 4.2以下,SecureRandom是基於老版的Bouncy Castle實現的。如果生成SecureRandom物件後馬上呼叫setSeed方法。SecureRandom會用使用者設定的seed代替預設的隨機源。使得每次生成隨機數時都是會使用相同的seed作為輸入。從而導致生成的隨機數是相同的。

解決方法:
1.不要使用自定義隨機源代替系統預設隨機源(推薦)除非有特殊需求.
2.在使用SecureRandom類時,不要呼叫這個建構函式
SecureRandom(byte[] seed)
3.不要呼叫這些設定種子的方法:

setSeed(long seed)
setSeed(byte[] seed)

4.可以在在呼叫setSeed方法前先呼叫任意nextXXX方法,可以通過nextBytes(byte[] bytes)避免這個問題。具體做法是呼叫setSeed方法前先呼叫一次nextBytes(byte[] bytes)方法。

3.安卓BroadCastReceiver安全風險

程式碼描述 : 安卓manifest.xml中廣播註冊程式碼。
程式碼:

<receiver android:name="com.baroad.demo.MyBroadCastReceiver" >  
     <intent-filter >  
     <action android:name="com.demo.action"/>  
     </intent-filter>  
     </receiver> 

解析:
BroadCastReceiver是Android 四大元件之一,應用非常廣泛,也非常簡單,但是我們平時在使用的過程中忽略了一個安全問題。別人很容易通過反編譯獲取到我們應用中的廣播,然後頻繁的向你的App中傳送廣播,那麼如何避免應用中註冊的廣播響應其他應用傳送的廣播呢,對於顯示的廣播除非是別人故意攻擊,一般很少出現響應別人的廣播,但是對於隱式的廣播就很容易出現上述問題,因為action很容易是一樣的,一旦是一樣的就出問題了.
修改方法:
1、在自己的應用中,在manifest.xml中註冊receiver的時候加入export屬性,android:exported=”false”。

ps: android:exported 是Android中的四大元件 Activity,Service,Provider,Receiver 四大元件中都會有的一個屬性。來表示是否允許跨程序呼叫,即該元件能不能被其他應用呼叫.預設值:如果包含有intent-filter 預設值為true; 沒有intent-filter預設值為false。

2、 自定義許可權,在manifest.xml中加入自定義許可權,然後再響應的BroadCastReceiver中加入這個許可權即可,在傳送廣播時將許可權作為引數一同發出,接收方在配置檔案裡新增相應的許可權

 //自定義一個許可權
<permission   
android:name="com.sdkj.permission.STARTBROAD"    
android:protectionLevel="normal"/>


<receiver android:name="com.baroad.demo.MyBroadCastReceiver"          android:permission="com.sdkj.permission.STARTBROAD">  
   <intent-filter >  
       <action android:name="com.demo.action"/>  
   </intent-filter>
  </receiver>

千萬不要忘記加入許可權

<uses-permission android:name="com.sdkj.permission.STARTBROAD"/>

傳送廣播時 :

    public void button(View view) {
        Intent intent = new Intent();
        intent.setAction("com.demo.action");
        sendBroadcast(intent,"com.sdkj.permission.STARTBROAD");
    }

這樣第三方應用只能獲得相應的許可權後才可以對B傳送訊息;

谷歌推薦使用第一種
3 安卓應用截圖安全風險

解析:我們開發程式的地方可能有的地方不想讓使用者截圖,或者不想讓其他程式為我們截圖,需要注意的地方

解決:
加入一行程式碼就可以解決:
this.getWindow().addFlags(WindowManager.LayoutParams.FLAG_SECURE);
這樣就能防止應用截圖了

4 Database配置模式安全風險

程式碼描述:安卓資料庫建立程式碼。
程式碼:

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
try {
database = openOrCreateDatabase("login.db",
    Context.MODE_WORLD_READABLE, null);
database.execSQL(CREATE_TABLE);   
} catch (SQLiteException e) {
 e.printStackTrace();
} 
et_name = (EditText) findViewById(R.id.et_name);
et_password = (EditText) findViewById(R.id.et_password);
btn_login = (Button) findViewById(R.id.btn_login);

解析:
Database配置模式安全風險源於:1)開發者在建立資料庫(Database)時沒有正確的選取合適的建立模式(MODE_PRIVATE、MODE_WORLD_READABLE以及MODE_WORLD_WRITEABLE)進行許可權控制,從而導致資料庫(Database)內容被惡意讀寫,造成賬戶密碼、身份資訊、以及其他敏感資訊的洩露,甚至攻擊者進一步實施惡意攻擊。
如果在開發中沒有使用正確的建立模式資料庫(Database)檔案,將會導致敏感資訊洩露危害,如個人賬戶密碼、身份資訊以及金融賬戶等重要敏感資訊。
**修改方法:
避免使用MODE_WORLD_WRITEABLE和MODE_WORLD_READABLE模式建立資料庫(Database),許可權不要開方太大,安全建議不要使用全域性可讀模式和全域性可寫模式建立資料庫;**

* 5 安卓LogCat安全風險

程式碼描述:LogCat列印敏感除錯資訊。

解析:
Logcat是我們開發中最常用的了,用它列印資訊,看程式是否執行到了這裡,和輸出一些資訊幫助我們開發程式,可是我們在列印的過程中,常常可能會列印一些關鍵的資訊,如使用者名稱,密碼,接獲取到有價值的隱私敏感資訊。.還有可能會讓攻擊者更加容易瞭解APP內部結構,方便破解和攻擊.

修改方法:
禁止隱私資訊的log,設定布林值來控制列印資訊,或者使用ProGuard等工具在APP的發行版本(release)中自動刪除Log.d()和Log.v()對應的程式碼.

6 安卓debuggable安全風險

程式碼描述:安卓manifest.xml檔案功能程式碼。

 <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" 
        android:debuggable="true">

解析:
android:debuggable=”true”應用存在debug除錯風險
debuggable 屬性有兩個值“true|false”;
只有Android:debuggable=”true”時我們才可以在手機上除錯Android程式。
但是當我們沒在AndroidManifest.xml中設定其debug屬性時:
使用Eclipse執行這種方式打包時其debug屬性為true,使用Eclipse匯出這種方式打包時其debug屬性為法false.
在使用ant打包時,其值就取決於ant的打包引數是release還是debug.

7 SharedPreferences儲存資料
解析:
在儲存特殊資料時,沒有對特殊資料進行加密處理,存在資料資訊洩漏風險。開放的許可權不要太大.

修改:
1.將Context.MODE_WORLD_READABLE改為Context.MODE_PRIVATE
Context.MODE_WORLD_READABLE:表示當前檔案可以被其他應用讀取。
Context.MODE_PRIVATE:表示當前檔案為預設操作模式,代表該檔案是私有資料,只能被應用本身訪問。
2.對儲存的資料採用MD5方式加密

ps :
MD5演算法具有以下特點:
1、壓縮性:任意長度的資料,算出的MD5值長度都是固定的。
2、容易計算:從原資料計算出MD5值很容易。
3、抗修改性:對原資料進行任何改動,哪怕只修改1個位元組,所得到的MD5值都有很大區別。
4、強抗碰撞:已知原資料和其MD5值,想找到一個具有相同MD5值的資料(即偽造資料)是非常困難的。
5、不可逆性:知道MD5值不會得到原資料.

public static String encrypt(String data, String mode) throws Exception {
MessageDigest md5 = MessageDigest.getInstance(mode);
md5.update(data.getBytes());
byte[] digest = md5.digest();
StringBuffer stringBuffer = new StringBuffer();
for (int i = 0; i < digest.length; i++) {
int val = ((int) digest[i]) & 0xff;
if (val < 16) {
stringBuffer.append("0");
}
stringBuffer.append(Integer.toHexString(digest[i]& 0xff));
}
return stringBuffer.toString();
}

先寫這麼多吧,寫了一下午昏昏漲漲的,第一次寫部落格,全是個人理解,如果有不對的地方,歡迎你的指正,如果有不明白的地方,樂於為你解答.如果有侵犯的地方,請聯絡我,會立即刪除.
做一個快樂的善於分享的開發者!