{{item}}
{{item.title}}
{{items.productName}}
{{items.price}}/年
{{item.title}}
部警SSL证书可实现网站HTTPS加密保护及身份的可信认证,防止传输数据的泄露或算改,提高网站可信度和品牌形象,利于SEO排名,为企业带来更多访问量,这也是网络安全法及PCI合规性的必备要求
前往SSL证书单向TLS认证已无法满足高安全需求场景,客户端证书双向认证(mTLS)通过 “双向证书校验” 杜绝非法接入与中间人攻击,是敏感数据传输的核心方案。本文以Android(Java)环境为核心,讲解mTLS原理、实现步骤与问题排查。
Android/Java对证书格式有要求,需先转换原始证书。
格式 | 用途 | 特点 |
---|---|---|
.p12/.pfx | 客户端证书(含私钥) | 二进制,需密码保护 |
.cer/.crt | 服务器 / CA 证书(仅公钥) | 二进制 / 文本,无密钥 |
.bks | Android 专用密钥库 | BouncyCastle 支持,存私钥与 CA 证书 |
需准备客户端密钥库(私钥 + 客户端证书)与服务器信任库(CA证书):
(1).p12转BKS(客户端密钥库)
keytool -importkeystore -srckeystore client.p12 -srcstoretype PKCS12 -destkeystore client.bks -deststoretype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath bcprov-jdk15on-1.70.jar
(2)服务器CA证书导入
keytool -import -fileCA.cer -alias root_CA-keystore truststore.bks -storetype BKS -provider org.bouncycastle.jce.provider.BouncyCastleProvider -providerpath bcprov-jdk15on-1.70.jar
注意事项
核心是自定义SSLContext,加载密钥库与信任库,配置到OkHttp。
<uses-permissionAndroid:name="android.permission.INTERNET" />
<application ...Android:usesCleartextTraffic="true"/>
implementation 'com.squareup.okhttp3:okhttp:4.11.0'
(1)加载客户端密钥库
private static KeyManager[] getClientKeyManagers(Context context, int keyStoreResId,
String keyStorePassword, String keyPassword) throws Exception {
InputStream in = context.getResources().openRawResource(keyStoreResId);
KeyStore keyStore = KeyStore.getInstance("BKS");
keyStore.load(in, keyStorePassword.toCharArray());
KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
kmf.init(keyStore, keyPassword.toCharArray());
in.close();
return kmf.getKeyManagers();
}
(2)加载服务器信任库
private static TrustManager[] getServerTrustManagers(Context context, intCAResId) throws Exception {
InputStream in = context.getResources().openRawResource(caResId);
CertificateFactory cf = CertificateFactory.getInstance("X.509");
X509CertificateCACert = (X509Certificate) cf.generateCertificate(in);
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
trustStore.setCertificateEntry("root_ca",CACert);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init(trustStore);
in.close();
TrustManager[] tms = tmf.getTrustManagers();
return new TrustManager[]{
new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] chain, String authType) {}
@Override
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
((X509TrustManager) tms[0]).checkServerTrusted(chain, authType);
chain[0].checkValidity(); // 效期校验
checkDomain(chain[0], "api.example.com"); // 域名校验
}
@Override
public X509Certificate[] getAcceptedIssuers() {
return ((X509TrustManager) tms[0]).getAcceptedIssuers();
}
private void checkDomain(X509Certificate cert, String expectedDomain) throws CertificateException {
// SAN字段或CN字段校验域名,不匹配抛异常
Collection<List<?>> san = cert.getSubjectAlternativeNames();
if (san != null) for (List<?> s : san) {
if ((int)s.get(0) == 2 && s.get(1).equals(expectedDomain)) return;
}
String cn = cert.getSubjectX500Principal().getName().split("CN=")[1].split(",")[0];
if (!cn.equals(expectedDomain)) throw new CertificateException("域名不匹配");
}
}
};
}
(3)构建 OkHttpClient
public static OkHttpClient getMutualAuthOkHttpClient(Context context, int clientKeyStoreResId,
String clientKeyStorePwd, String clientKeyPwd,
int serverCaResId) throws Exception {
KeyManager[] kms = getClientKeyManagers(context, clientKeyStoreResId, clientKeyStorePwd, clientKeyPwd);
TrustManager[] tms = getServerTrustManagers(context, serverCaResId);
SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
sslContext.init(kms, tms, new SecureRandom());
return new OkHttpClient.Builder()
.sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager) tms[0])
.hostnameVerifier(HttpsURLConnection.getDefaultHostnameVerifier())
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build();
}
public class MutualAuthActivity extends AppCompatActivity {
private static final String API_URL = "https://api.example.com/mutual-auth/test";
private static final String KEY_STORE_PWD = "your_pwd";
private static final String KEY_PWD = "your_pwd";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mutual_auth);
new Thread(() -> {
try {
OkHttpClient client = SSLUtils.getMutualAuthOkHttpClient(
this, R.raw.client_bks, KEY_STORE_PWD, KEY_PWD, R.raw.ca_cer);
Request request = new Request.Builder().url(API_URL).build();
Response response = client.newCall(request).execute();
if (response.isSuccessful()) {
String res = response.body().string();
runOnUiThread(() -> Toast.makeText(this, "成功:" + res, Toast.LENGTH_SHORT).show());
} else {
runOnUiThread(() -> Toast.makeText(this, "失败,状态码:" + response.code(), Toast.LENGTH_SHORT).show());
}
}CAtch (Exception e) {
runOnUiThread(() -> Toast.makeText(this, "异常:" + e.getMessage(), Toast.LENGTH_SHORT).show());
}
}).start();
}
}
mTLS通过双向校验保障高安全通信,Android/Java实现核心是自定义SSLContext与OkHttp配置。需注意证书转换、兼容性与私钥安全,是金融、医疗等场景的必要安全手段,符合合规要求。
Dogssl.cn拥有20年网络安全服务经验,提供构涵盖国际CA机构Sectigo、Digicert、GeoTrust、GlobalSign,以及国内CA机构CFCA、沃通、vTrus、上海CA等数十个SSL证书品牌。全程技术支持及免费部署服务,如您有SSL证书需求,欢迎联系!