在移动应用开发中,网络通信安全至关重要。本文将详细介绍Android平台上的安全通信实现方案,包括HTTPS协议、证书验证、双向认证等核心技术,帮助开发者构建安全可靠的网络通信机制。
HTTPS(超文本传输安全协议)是HTTP协议的安全版本,通过SSL/TLS协议进行加密通信,确保数据传输的安全性。
握手阶段
数据传输阶段
数字证书是由可信的证书颁发机构(CA)签发的电子文档,用于证明公钥持有者的身份。
证书链是一系列证书的集合,从终端实体证书到根证书:
public class HttpsUtils {
public static OkHttpClient getHttpsClient() {
try {
// 创建信任管理器
X509TrustManager trustManager = new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) {
// 验证客户端证书
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) {
// 验证服务器证书
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
};
// 创建SSL上下文
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[]{trustManager}, new SecureRandom());
// 配置OkHttpClient
return new OkHttpClient.Builder()
.sslSocketFactory(sslContext.getSocketFactory(), trustManager)
.hostnameVerifier((hostname, session) -> true)
.build();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
public class HttpsDemo {
public void demoHttpsClient() {
// 获取配置好的HTTPS客户端
OkHttpClient client = HttpsUtils.getHttpsClient();
// 构建请求
Request request = new Request.Builder()
.url("https://api.example.com/data")
.build();
// 发起请求
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
String responseData = response.body().string();
// 处理响应数据
}
}
});
}
}
Android 7.0引入的Network Security Configuration允许应用通过XML文件自定义网络安全设置。
<network-security-config>
<base-config cleartextTrafficPermitted="false">
<trust-anchors>
<certificates src="system" />
<certificates src="user" />
trust-anchors>
base-config>
<domain-config>
<domain includeSubdomains="true">example.comdomain>
<pin-set expiration="2022-01-01">
<pin digest="SHA-256">7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=pin>
<pin digest="SHA-256">fwza0LRMXouZHRC8Ei+4PyuldPDcf3UKgO/04cDM1oE="pin>
pin-set>
domain-config>
network-security-config>
<application
android:networkSecurityConfig="@xml/network_security_config"
... >
...
application>
public class CertificateUtils {
public static SSLSocketFactory getSSLSocketFactory(Context context, int[] certificates) {
try {
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null);
for (int i = 0; i < certificates.length; i++) {
InputStream certificate = context.getResources().openRawResource(certificates[i]);
keyStore.setCertificateEntry(String.valueOf(i), certificateFactory.generateCertificate(certificate));
certificate.close();
}
SSLContext sslContext = SSLContext.getInstance("TLS");
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());
return sslContext.getSocketFactory();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
public class CustomTrustManager implements X509TrustManager {
private X509TrustManager defaultTrustManager;
private X509TrustManager localTrustManager;
public CustomTrustManager(X509TrustManager localTrustManager) {
try {
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init((KeyStore) null);
defaultTrustManager = (X509TrustManager) tmf.getTrustManagers()[0];
this.localTrustManager = localTrustManager;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
try {
defaultTrustManager.checkClientTrusted(chain, authType);
} catch (CertificateException e) {
localTrustManager.checkClientTrusted(chain, authType);
}
}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
try {
defaultTrustManager.checkServerTrusted(chain, authType);
} catch (CertificateException e) {
localTrustManager.checkServerTrusted(chain, authType);
}
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return defaultTrustManager.getAcceptedIssuers();
}
}
证书固定是一种安全技术,通过预先指定服务器证书的公钥哈希值,防止中间人攻击。
public class CertificatePinningUtils {
public static OkHttpClient getPinnedClient() {
String hostname = "api.example.com";
String[] pins = {
"sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", // 主证书
"sha256/BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=" // 备用证书
};
return new OkHttpClient.Builder()
.certificatePinner(new CertificatePinner.Builder()
.add(hostname, pins)
.build())
.build();
}
}
public class CertificatePinningDemo {
public void demoCertificatePinning() {
// 获取配置好的证书固定客户端
OkHttpClient client = CertificatePinningUtils.getPinnedClient();
// 构建请求
Request request = new Request.Builder()
.url("https://api.example.com/data")
.build();
// 发起请求
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
// 如果证书不匹配,这里会收到SSLPeerUnverifiedException
e.printStackTrace();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
String responseData = response.body().string();
// 处理响应数据
}
}
});
}
}
openssl s_client -servername example.com -connect example.com:443 | openssl x509 -noout -fingerprint -sha256
双向认证要求客户端和服务器都提供证书进行身份验证,提供更高级别的安全保障。
public class MutualTLSUtils {
public static OkHttpClient getMutualTLSClient(Context context, String clientCertPath, String password) {
try {
// 加载客户端证书
KeyStore clientKeyStore = KeyStore.getInstance("PKCS12");
InputStream clientCertStream = context.getAssets().open(clientCertPath);
clientKeyStore.load(clientCertStream, password.toCharArray());
// 配置密钥管理器
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(clientKeyStore, password.toCharArray());
// 配置信任管理器
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null);
trustManagerFactory.init(trustStore);
// 创建SSL上下文
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), new SecureRandom());
// 配置OkHttpClient
return new OkHttpClient.Builder()
.sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager) trustManagerFactory.getTrustManagers()[0])
.hostnameVerifier((hostname, session) -> true)
.build();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
public class MutualTLSDemo {
public void demoMutualTLS(Context context) {
String clientCertPath = "client.p12";
String password = "证书密码";
// 获取配置好的双向认证客户端
OkHttpClient client = MutualTLSUtils.getMutualTLSClient(context, clientCertPath, password);
// 构建请求
Request request = new Request.Builder()
.url("https://api.example.com/data")
.build();
// 发起请求
client.newCall(request).enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
String responseData = response.body().string();
// 处理响应数据
}
}
});
}
}
证书存储安全
证书更新机制
证书验证
<network-security-config>
<base-config cleartextTrafficPermitted="false">
<trust-anchors>
<certificates src="system" />
trust-anchors>
base-config>
network-security-config>
OkHttpClient client = new OkHttpClient.Builder()
.connectionSpecs(Arrays.asList(
ConnectionSpec.MODERN_TLS,
ConnectionSpec.COMPATIBLE_TLS
))
.build();
Request request = new Request.Builder()
.header("X-Requested-With", "XMLHttpRequest")
.header("X-Content-Type-Options", "nosniff")
.build();
public class DataEncryptionUtils {
public static String encrypt(String data, SecretKey key) {
try {
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] encryptedData = cipher.doFinal(data.getBytes());
return Base64.encodeToString(encryptedData, Base64.DEFAULT);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
public class SignatureUtils {
public static String sign(Map<String, String> params, String secretKey) {
// 按键排序
TreeMap<String, String> sortedParams = new TreeMap<>(params);
// 构建签名字符串
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String> entry : sortedParams.entrySet()) {
sb.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
}
sb.append("key=").append(secretKey);
// 计算MD5
return MD5Utils.encrypt(sb.toString());
}
}
证书过期
证书不信任
证书固定失败
public class SSLErrorHandler {
public static void handleSSLError(SSLException e) {
if (e instanceof SSLPeerUnverifiedException) {
// 证书验证失败
Log.e("SSL", "证书验证失败", e);
} else if (e instanceof SSLProtocolException) {
// 协议错误
Log.e("SSL", "SSL协议错误", e);
} else {
// 其他SSL错误
Log.e("SSL", "SSL通信错误", e);
}
}
}
public class ProxyUtils {
public static OkHttpClient getProxyClient(Proxy proxy) {
return new OkHttpClient.Builder()
.proxy(proxy)
.proxyAuthenticator((route, response) -> {
// 处理代理认证
return response.request();
})
.build();
}
}
答:主要区别包括:
答:SSL/TLS通过握手过程建立安全通信:
答:可以通过以下方式:
答:建议采取以下措施:
答:可以采取以下措施:
答:建议采取以下措施: