{{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证书需求,欢迎联系!