HTTPS android 到服务器通信总是 returns 403 响应

Https android to server communication always returns 403 response

过去两天我一直坚持这个问题,我必须使用客户端证书对服务器实施相互身份验证。我的 .pfx 文件位于 res 目录中的 raw 文件夹中。

我在 res/raw/certificate.pfx

我还在 android 中实现了 HttpUrlConnection 并将 SSLSocketFactory 设置为我从我的证书生成的那个。但问题是服务器总是 returns 403。我尝试添加所有请求 属性,包括 "User Agent"。但似乎没有任何效果。

我附上了下面的代码。我信任这样的证书。

public SSLSocketFactory getSSLSocketFactory_Certificate(String keyStoreType, int keystoreResId)
        throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException, KeyManagementException, NoSuchProviderException {

    InputStream caInput = context.getResources().openRawResource(keystoreResId);

    // creating a KeyStore containing trusted CAs

    if (keyStoreType == null || keyStoreType.length() == 0) {
        keyStoreType = KeyStore.getDefaultType();
    }
    KeyStore keyStore = KeyStore.getInstance(keyStoreType);

    keyStore.load(caInput, "".toCharArray());

    // creating a TrustManager that trusts the CAs in the KeyStore

    String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
    TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
    tmf.init(keyStore);

    TrustManager[] wrappedTrustManagers = getWrappedTrustManagers(tmf.getTrustManagers());

    SSLContext sslContext = SSLContext.getInstance("TLS");
    sslContext.init(null, wrappedTrustManagers, null);

    return sslContext.getSocketFactory();
}

最后在我的 activity 中,我按如下方式进行 https 调用

URL url = null;
        HttpURLConnection conn;
        try {
            url = new URL("https://example.com");
            conn = (HttpURLConnection) url.openConnection();
            if (conn instanceof HttpsURLConnection) {
                ((HttpsURLConnection) conn).setSSLSocketFactory(sslSocketFactory);
            }
            conn.setRequestMethod("GET");
            conn.setRequestProperty("Accept", "application/json");
            conn.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36");

            int responseCode = conn.getResponseCode();
            System.out.println("Server response code" + responseCode);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

但是结果总是403 forbidden。我不确定我哪里出错了。有人请帮助我。

啊..终于我自己找到了问题。我所缺少的是我在加载证书后未能使用密钥库初始化我的密钥库工厂。

public SSLSocketFactory getSSLSocketFactory_Certificate(String keyStoreType, int keystoreResId)
        throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException, KeyManagementException, NoSuchProviderException, UnrecoverableKeyException {

    InputStream caInput = context.getResources().openRawResource(keystoreResId);

    // creating a KeyStore containing trusted CAs

    if (keyStoreType == null || keyStoreType.length() == 0) {
        keyStoreType = KeyStore.getDefaultType();
    }
    KeyStore keyStore = KeyStore.getInstance(keyStoreType);
    keyStore.load(caInput, "".toCharArray());

    // creating a TrustManager that trusts the CAs in the KeyStore

    String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
    TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
    tmf.init(keyStore);

    TrustManager[] wrappedTrustManagers = getWrappedTrustManagers(tmf.getTrustManagers());

    SSLContext sslContext = SSLContext.getInstance("TLS");
    KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
    kmf.init(keyStore, "".toCharArray());

    sslContext.init(kmf.getKeyManagers(), wrappedTrustManagers, null);
    return sslContext.getSocketFactory();
}

这些台词对我有用。

SSLContext sslContext = SSLContext.getInstance("TLS");
    KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
    kmf.init(keyStore, "".toCharArray());

    sslContext.init(kmf.getKeyManagers(), wrappedTrustManagers, null);

希望它能对某人有所帮助。 :)