Android SSL SNI 连接问题
Android SSL SNI connection issues
我有一个用于使用和更新网络服务器数据的应用程序,最近,由于存储了个人信息,应用程序所有者决定切换到安全连接。
服务器已经设置为 SNI,我已经使用 digicert 检查了它,服务器工作正常并且似乎设置正确,但 没有 在其备用名称中包含路径 *.host.com(我不确定这对于 SNI 是否正常)。
iOS 非常有效,但是在 Android 上我得到了这个错误:
java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
我目前的连接方式是这样的:
URL url = new URL(postURL);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
SSLContext sc;
sc = SSLContext.getInstance("TLS");
sc.init(null, null, new java.security.SecureRandom());
conn.setSSLSocketFactory(sc.getSocketFactory());
String userpass = "bob" + ":" + "12345678";
String basicAuth = "Basic " + Base64.encodeToString(userpass.getBytes(), Base64.DEFAULT);
conn.setRequestProperty("Authorization", basicAuth);
conn.setReadTimeout(7000);
conn.setConnectTimeout(7000);
conn.setRequestMethod("POST");
conn.setDoInput(true);
conn.connect();
InputStream instream = conn.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(instream));
StringBuilder everything = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
everything.append(line);
}
JSONObject jsonObject = new JSONObject(everything.toString());
return jsonObject;
我不太确定这里的问题是什么,但尝试连接到 https://sni.velox.ch/ 给了我一个看起来很成功的长答案。
此外,我这里确实有证书的 pem 密钥,但我不知道如何在这种情况下添加它。
通常在使用自签名证书时会出现此错误,在这种情况下,您必须在发出请求时使用该证书。
此外,您可能会收到此错误,因为不包括路径 *.host.com.
您可以尝试使用以下代码在构建 HttpsURLConnection
时通过您的证书。请不要忘记将 ca.pem 文件复制到资产文件夹。
private HttpsURLConnection buildSslServerConnection() {
HttpsURLConnection urlConnection = null;
try {
// Load CAs from an InputStream
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream caInput = new BufferedInputStream(context.getAssets().open("ca.pem"));
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
} finally {
caInput.close();
}
// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// Create an SSLContext that uses our TrustManager
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
// Tell the URLConnection to use a SocketFactory from our SSLContext
urlConnection = (HttpsURLConnection) url.openConnection();
urlConnection.setSSLSocketFactory(context.getSocketFactory());
urlConnection.setRequestMethod("POST");
urlConnection.setRequestProperty("Authorization", "Basic" + Base64.encodeToString(userpass.getBytes(), Base64.DEFAULT));
urlConnection.setConnectTimeout(7000);
urlConnection.setReadTimeout(7000);
urlConnection.setInstanceFollowRedirects(false);
urlConnection.setUseCaches(false);
urlConnection.setAllowUserInteraction(false);
urlConnection.setDoOutput(false);
} catch (KeyManagementException e) {
LOG.error("Error while checking server connectivity: ", e);
} catch (CertificateException e) {
LOG.error("Error while checking server connectivity: ", e);
} catch (FileNotFoundException e) {
LOG.error("Error while checking server connectivity: ", e);
} catch (KeyStoreException e) {
LOG.error("Error while checking server connectivity: ", e);
} catch (NoSuchAlgorithmException e) {
LOG.error("Error while checking server connectivity: ", e);
} catch (MalformedURLException e) {
LOG.error("Error while checking server connectivity: ", e);
} catch (IOException e) {
LOG.error("Error while checking server connectivity: ", e);
}
return urlConnection;
}
希望对您有所帮助。
我有一个用于使用和更新网络服务器数据的应用程序,最近,由于存储了个人信息,应用程序所有者决定切换到安全连接。
服务器已经设置为 SNI,我已经使用 digicert 检查了它,服务器工作正常并且似乎设置正确,但 没有 在其备用名称中包含路径 *.host.com(我不确定这对于 SNI 是否正常)。
iOS 非常有效,但是在 Android 上我得到了这个错误:
java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.
我目前的连接方式是这样的:
URL url = new URL(postURL);
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
SSLContext sc;
sc = SSLContext.getInstance("TLS");
sc.init(null, null, new java.security.SecureRandom());
conn.setSSLSocketFactory(sc.getSocketFactory());
String userpass = "bob" + ":" + "12345678";
String basicAuth = "Basic " + Base64.encodeToString(userpass.getBytes(), Base64.DEFAULT);
conn.setRequestProperty("Authorization", basicAuth);
conn.setReadTimeout(7000);
conn.setConnectTimeout(7000);
conn.setRequestMethod("POST");
conn.setDoInput(true);
conn.connect();
InputStream instream = conn.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(instream));
StringBuilder everything = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
everything.append(line);
}
JSONObject jsonObject = new JSONObject(everything.toString());
return jsonObject;
我不太确定这里的问题是什么,但尝试连接到 https://sni.velox.ch/ 给了我一个看起来很成功的长答案。
此外,我这里确实有证书的 pem 密钥,但我不知道如何在这种情况下添加它。
通常在使用自签名证书时会出现此错误,在这种情况下,您必须在发出请求时使用该证书。
此外,您可能会收到此错误,因为不包括路径 *.host.com.
您可以尝试使用以下代码在构建 HttpsURLConnection
时通过您的证书。请不要忘记将 ca.pem 文件复制到资产文件夹。
private HttpsURLConnection buildSslServerConnection() {
HttpsURLConnection urlConnection = null;
try {
// Load CAs from an InputStream
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream caInput = new BufferedInputStream(context.getAssets().open("ca.pem"));
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
} finally {
caInput.close();
}
// Create a KeyStore containing our trusted CAs
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
// Create a TrustManager that trusts the CAs in our KeyStore
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
// Create an SSLContext that uses our TrustManager
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
// Tell the URLConnection to use a SocketFactory from our SSLContext
urlConnection = (HttpsURLConnection) url.openConnection();
urlConnection.setSSLSocketFactory(context.getSocketFactory());
urlConnection.setRequestMethod("POST");
urlConnection.setRequestProperty("Authorization", "Basic" + Base64.encodeToString(userpass.getBytes(), Base64.DEFAULT));
urlConnection.setConnectTimeout(7000);
urlConnection.setReadTimeout(7000);
urlConnection.setInstanceFollowRedirects(false);
urlConnection.setUseCaches(false);
urlConnection.setAllowUserInteraction(false);
urlConnection.setDoOutput(false);
} catch (KeyManagementException e) {
LOG.error("Error while checking server connectivity: ", e);
} catch (CertificateException e) {
LOG.error("Error while checking server connectivity: ", e);
} catch (FileNotFoundException e) {
LOG.error("Error while checking server connectivity: ", e);
} catch (KeyStoreException e) {
LOG.error("Error while checking server connectivity: ", e);
} catch (NoSuchAlgorithmException e) {
LOG.error("Error while checking server connectivity: ", e);
} catch (MalformedURLException e) {
LOG.error("Error while checking server connectivity: ", e);
} catch (IOException e) {
LOG.error("Error while checking server connectivity: ", e);
}
return urlConnection;
}
希望对您有所帮助。