保護Android上的通訊安全
隨著最近的所有資料洩露,隱私已成為一個重要的主題。幾乎每個應用程式都通過網路進行通訊,因此考慮使用者資訊的安全性非常重要。在這篇文章中,您將瞭解保護Android應用程式通訊的最新實踐。
一 使用HTTPS
在開發應用程式時,最好將網路請求限制為必要的網路請求。對於必要的,請確保它們是通過HTTPS而不是HTTP製作的。HTTPS是一種加密流量的協議,因此竊聽者無法輕易攔截它。關於Android的好處是遷移就像將URL從http更改為https一樣簡單。
URL url =` `new` `URL(``"[https://example.com](https://example.com/)"``);` `HttpsURLConnection httpsURLConnection = (HttpsURLConnection)url.openConnection();` `httpsURLConnection.connect();`
事實上,Android N及更高版本可以使用 Android的網路安全配置 強制執行HTTPS 。
在Android Studio中,選擇專案的 app / res / xml 目錄。如果 xml 目錄尚不存在,請建立它。選擇它,然後單擊 檔案>新檔案 。稱之為 network_security_config.xml 。該檔案的格式如下:
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <domain-config cleartextTrafficPermitted="false"> <domain includeSubdomains="true">example.com</domain> </domain-config> </network-security-config>
要告訴Android使用此檔案,請將檔名新增到AndroidManifest.xml檔案中的application標記:
<application android:networkSecurityConfig="@xml/network_security_config"
二 更新加密提供程式
多年來,HTTPS協議已被多次利用。當安全研究人員報告漏洞時,缺陷通常會被修補。應用修補程式可確保應用程式的網路連線使用最新的行業標準協議。最新版本的協議包含的弱點比以前少。
要更新 加密提供程式 ,您需要包含Google Play服務。在build.gradle的模組檔案中,將以下行新增到dependencies部分:
implementation 'com.google.android.gms:play-services-safetynet:15.0.1'
該 安全網 服務API還有更多的功能,包括 安全瀏覽 API,檢查的網址,看看他們是否已被標記為已知威脅,以及 驗證碼 API,以防止垃圾郵件和其他惡意流量您的應用程式。
同步完成後搖籃,你可以呼叫 ProviderInstaller
的 installIfNeededAsync
方法:
public class MainActivity extends Activity implements ProviderInstaller.ProviderInstallListener { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ProviderInstaller.installIfNeededAsync(this, this); } }
onProviderInstalled()當提供程式成功更新或已更新時,將呼叫此方法。否則,onProviderInstallFailed(int errorCode, Intent recoveryIntent)被稱為。
三 證書和公鑰固定
當您與伺服器建立HTTPS連線時,伺服器會顯示數字證書並由Android驗證,以確保連線安全。證書可以使用來自中間證書頒發機構的證書進行簽名。中間許可權使用的此證書可以由另一箇中間許可權簽名,依此類推,只要最後一個證書由已被Android作業系統信任的根證書頒發機構簽名,這是可信的。
如果信任鏈中的任何證書無效,則連線不安全。雖然這是一個很好的系統,但它並非萬無一失。攻擊者可能會指示Android作業系統接受自定義證書。攔截代理可以擁有受信任的證書,如果裝置由公司控制,則公司可能已將裝置配置為接受其自己的證書。這些場景允許“中間人”攻擊,允許解密和讀取HTTPS流量。
通過檢查根據預期證書副本提供的伺服器證書,可以解決證書鎖定問題。這可以防止在證書與預期證書不同時建立連線。
為了在Android N及更高版本上實現固定,您需要將證書的雜湊(稱為引腳)新增到network_security_config.xml檔案中。這是一個示例實現:
<?xml version="1.0" encoding="utf-8"?> <network-security-config> <domain-config cleartextTrafficPermitted="false"> <domain includeSubdomains="true">duckduckgo.com</domain> <pin-set> <pin digest="SHA-256">lFL47+i9MZkLqDTjnbPTx2GZbGmRfvF3GkEh+J+1F3g=</pin> <pin digest="SHA-256">w9MWhhnFZDSPWTFBjaoeGuClsrCs7Z70lG7YNlo8t+s=</pin> </pin-set> </domain-config> </network-security-config>
要查詢特定站點的引腳,您可以轉到 SSL實驗室 ,進入該站點,然後單擊“ 提交” 。或者,如果您正在為公司開發應用程式,您可以向公司詢問。
注意:如果您需要支援執行早於Android N的作業系統版本的裝置,則可以使用 TrustKit 庫。它以完全相同的方式使用網路安全配置檔案。
四 消毒和驗證
到目前為止,所有的保護措施,您的連線應該是非常安全的。即便如此,也不要忘記定期程式設計驗證。盲目信任從網路收到的資料是不安全的。一個好的程式設計實踐是“按合同設計”,其中您的方法的輸入和輸出滿足定義特定介面期望的合同。
例如,如果您的伺服器需要48個字元或更少的字串,請確保該介面最多隻返回48個字元。
if (editText.getText().toString().length() <= 48) { ; //return something... } else { ; //return default or error }
如果您只是期望來自伺服器的數字,您的輸入應該檢查這一點。雖然這有助於防止無辜的錯誤,但它也降低了注入和記憶體損壞攻擊的可能性。當資料傳遞給 NDK 或 JNI -native C和C ++程式碼時尤其如此。
將資料傳送到伺服器也是如此。不要盲目傳送資料,特別是如果它是使用者生成的。例如,限制使用者輸入的長度是一種好習慣,特別是如果它將由SQL伺服器或將執行程式碼的任何技術執行。
雖然保護伺服器免受攻擊超出了本文的範圍,但作為移動開發人員,您可以通過刪除伺服器正在使用的語言的字元來完成您的工作。這樣,輸入不易受到注入攻擊。一些示例是在對使用者輸入不重要時剝離引號,分號和斜槓:
string = string.replace("\\", "").replace(";", "").replace("\"", "").replace("\'", "");
如果您確切知道預期的格式,則應檢查此格式。一個很好的例子是電子郵件驗證
private final String emailRegexString = "^[A-Za-z0-9._%+\\-]+@[A-Za-z0-9.\\-]+\\.[A-Za-z]{2,4}$"; private boolean isValidEmailString(String emailString) { return emailString != null &&Pattern.compile(emailRegexString).matcher(emailString).matches(); }
也可以檢查檔案。如果您要將照片傳送到伺服器,則可以將其檢查為有效照片。前兩個位元組和最後兩個位元組總是FF D8和FF D9 為JPEG格式。
private static boolean isValidJPEGAtPath(String pathString) throws IOException { RandomAccessFile randomAccessFile = null; try { randomAccessFile = new RandomAccessFile(pathString, "r"); long length = randomAccessFile.length(); if (length < 10L) { return false; } byte[] start = new byte[2]; randomAccessFile.readFully(start); randomAccessFile.seek(length - 2); byte[] end = new byte[2]; randomAccessFile.readFully(end); return start[0] == -1 && start[1] == -40 && end[0] == -1 && end[1] == -39; } finally { if (randomAccessFile != null) { randomAccessFile.close(); } } }
顯示直接顯示來自伺服器的訊息的錯誤警報時要小心。錯誤訊息可能會洩露私人除錯或安全相關資訊。解決方案是讓伺服器傳送錯誤程式碼,客戶端查詢該錯誤程式碼以顯示預定義的訊息。
五 與其他應用程式通訊
當您保護與裝置之間的通訊時,保護IPC也很重要。有些情況下,開發人員已經離開了共享檔案或已經實現了套接字來交換敏感資訊。這不安全。最好使用Intent。您可以通過提供如下所示的包名來使用Intent傳送資料:
Intent intent = new Intent(); intent.setComponent(new ComponentName("com.example.app","com.example.app.TheActivity")); intent.putExtra("UserInfo", "Example string"); startActivity(intent);
要將資料廣播到多個應用,您應該強制只有使用您的簽名金鑰簽名的應用才能獲取資料。否則,任何註冊接收廣播的應用都可以讀取您傳送的資訊。同樣,如果您已註冊接收廣播,則惡意應用可以向您的應用傳送廣播。傳送和接收使用簽名作為protectionLevel的廣播時,您可以使用許可權。您可以在清單檔案中定義自定義許可權,如下所示:
<permission android:name="com.example.mypermission" android:protectionLevel="signature"/>
然後您可以像這樣授予許可權:
<uses-permission android:name="com.example.mypermission"/>
兩個應用程式都需要在清單檔案中具有許可權才能使其正常工作。傳送廣播:
Intent intent = new Intent(); intent.putExtra("UserInfo", "Example string"); intent.setAction("com.example.SOME_NOTIFICATION"); sendBroadcast(intent, "com.example.mypermission");
或者,您可以在傳送廣播時將其限制為與指定包匹配的一組應用。在清單檔案中設定為將排除從應用程式外部接收的廣播。 setPackage(String)
android:exported
false
六 端到端加密
瞭解HTTPS保護網路通訊的限制非常重要。在大多數HTTPS實現中,加密在伺服器處終止。例如,您與公司伺服器的連線可能是通過HTTPS進行的,但是一旦該流量到達伺服器,它就會被解密。然後可以通過建立另一個HTTPS會話或通過未加密的方式將其轉發到其他伺服器。公司能夠檢視已傳送的資訊,並且在大多數情況下,這是業務運營的要求。但是,這也意味著公司可以將資訊傳遞給未加密的第三方。
最近出現了一種稱為“端到端加密”的趨勢,其中只有兩個終端通訊裝置可以讀取流量。一個很好的例子是加密的聊天應用程式,其中兩個移動裝置通過伺服器相互通訊; 只有傳送者和接收者才能閱讀彼此的訊息。
一個幫助您理解端到端加密的類比是想象您希望某人向您傳送只有您可以閱讀的訊息。為此,您可以在保留掛鎖金鑰(私鑰)的同時為其提供一個帶有開啟掛鎖的盒子(公鑰)。使用者編寫訊息,將其放入框中,鎖定掛鎖並將其發回給您。只有您可以閱讀該訊息,因為您是唯一一個帶鑰匙解鎖掛鎖的人。
通過端到端加密,兩個使用者都可以互相傳送金鑰。伺服器僅提供通訊服務,但無法讀取通訊內容。雖然實現細節超出了本文的範圍,但它是一項功能強大的技術。如果你想了解更多關於這種方法的知識,一個很好的起點是開源 訊號專案 的 GitHub回購 。
結論
隨著GDPR等所有新的隱私法律,安全性變得越來越重要。這通常是移動應用程式開發的一個被忽視的方面。
在本教程中,您已經介紹了安全性最佳實踐,包括使用HTTPS,證書鎖定,資料清理和端到端加密。在開發移動應用程式時,這些最佳實踐應作為安全性的基礎。如果您有任何疑問,請隨時將它們留在下面,當您在這裡時,請檢視我的其他一些有關Android應用程式安全性的教程!

image
想學習更多Android知識,或者獲取相關資料請加入Android技術開發交流2群:935654177。本群可免費獲取Gradle,RxJava,小程式,Hybrid,移動架構,NDK,React Native,效能優化等技術教程!