如何在 Android 应用程序中绕过 SSL 证书验证?
How to bypass SSL certificate validation in Android app?
我的 Android 应用程序应该能够与任何启用 SSL 的服务器通信。由于我的应用程序是演示应用程序,我的客户在登录时在应用程序中添加了他们自己的 SSL 服务器详细信息,所以我不知道我需要验证哪个 SSL 证书。
以下是我之前的代码。
public SSLSocketFactory getSSLSocketFactory(String hostname) {
try {
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, new X509TrustManager[] { new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
} }, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());
} catch (Exception e) {
e.printStackTrace();
}
return HttpsURLConnection.getDefaultSSLSocketFactory();
}
当我更新到 playstore 时,它被拒绝了,原因如下
要正确处理 SSL 证书验证,请更改自定义 X509TrustManager 接口的 checkServerTrusted 方法中的代码,以便在服务器提供的证书不符合您的期望时引发 CertificateException 或 IllegalArgumentException。对于技术问题,您可以 post 到 Stack Overflow 并使用标签“android-security”和“TrustManager”。
我想更新我的代码,类似于此
public static HttpClient wrapClient(HttpClient base) {
try {
SSLContext ctx = SSLContext.getInstance("TLS");
X509TrustManager tm = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException { }
public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException { }
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
ctx.init(null, new TrustManager[]{tm}, null);
SSLSocketFactory ssf = new SSLSocketFactory(ctx);
ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
ClientConnectionManager ccm = base.getConnectionManager();
SchemeRegistry sr = ccm.getSchemeRegistry();
sr.register(new Scheme("https", ssf, 443));
return new DefaultHttpClient(ccm, base.getParams());
} catch (Exception ex) {
return null;
}
}
Playstore 接受这个吗?有没有更好的方法来处理这个问题?
提前致谢。
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.net.URLConnection;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.cert.X509Certificate;
public class Example {
public static void main(String[] args) throws Exception {
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
}
};
// Install the all-trusting trust manager
SSLContext sc = SSLContext.getInstance("SSL"); // Add in try catch block if you get error.
sc.init(null, trustAllCerts, new java.security.SecureRandom()); // Add in try catch block if you get error.
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
// Create all-trusting host name verifier
HostnameVerifier allHostsValid = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
// Install the all-trusting host verifier
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
URL url = new URL("https_url_here");
URLConnection con = url.openConnection();
Reader reader = new InputStreamReader(con.getInputStream());
while (true) {
int ch = reader.read();
if (ch==-1) {
break;
}
System.out.print((char)ch);
}
}
}
使用这个技巧时要小心!跳过证书验证是危险的,只能在测试环境中进行。
引用解决方案:
https://gist.github.com/aembleton/889392
以下代码禁用对 HttpsUrlConnection 的任何新实例的 SSL 证书检查:
/**
* Disables the SSL certificate checking for new instances of {@link HttpsURLConnection} This has been created to
* aid testing on a local box, not for use on production.
*/
public static void disableSSLCertificateChecking() {
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
@Override
public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
// Not implemented
}
@Override
public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
// Not implemented
}
} };
try {
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { @Override public boolean verify(String hostname, SSLSession session) { return true; } });
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
如果有人想在 NativeScript Android 应用程序中禁用 SSL 证书检查,这里是将 代码转换为 JavaScript 的方法:
const disableSSLCertificateCheckin = function () {
const trustAllCerts = [new javax.net.ssl.X509TrustManager({
getAcceptedIssuers: function () {
return null
},
checkClientTrusted: function (arg0, arg1) {
// Not implemented
},
checkServerTrusted: function (arg0, arg1) {
// Not implemented
},
})]
try {
const sc = javax.net.ssl.SSLContext.getInstance('TLS')
sc.init(null, trustAllCerts, new java.security.SecureRandom())
javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory())
javax.net.ssl.HttpsURLConnection.HttpsURLConnection.setDefaultHostnameVerifier(
new javax.net.ssl.HostnameVerifier({
verify: function (hostname, session) {
return true
}
})
)
} catch (e) {
console.log('e :>> ', e);
}
}
disableSSLCertificateCheckin()
谢谢!
我的 Android 应用程序应该能够与任何启用 SSL 的服务器通信。由于我的应用程序是演示应用程序,我的客户在登录时在应用程序中添加了他们自己的 SSL 服务器详细信息,所以我不知道我需要验证哪个 SSL 证书。
以下是我之前的代码。
public SSLSocketFactory getSSLSocketFactory(String hostname) {
try {
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, new X509TrustManager[] { new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
} }, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());
} catch (Exception e) {
e.printStackTrace();
}
return HttpsURLConnection.getDefaultSSLSocketFactory();
}
当我更新到 playstore 时,它被拒绝了,原因如下
要正确处理 SSL 证书验证,请更改自定义 X509TrustManager 接口的 checkServerTrusted 方法中的代码,以便在服务器提供的证书不符合您的期望时引发 CertificateException 或 IllegalArgumentException。对于技术问题,您可以 post 到 Stack Overflow 并使用标签“android-security”和“TrustManager”。
我想更新我的代码,类似于此
public static HttpClient wrapClient(HttpClient base) {
try {
SSLContext ctx = SSLContext.getInstance("TLS");
X509TrustManager tm = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException { }
public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException { }
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
ctx.init(null, new TrustManager[]{tm}, null);
SSLSocketFactory ssf = new SSLSocketFactory(ctx);
ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
ClientConnectionManager ccm = base.getConnectionManager();
SchemeRegistry sr = ccm.getSchemeRegistry();
sr.register(new Scheme("https", ssf, 443));
return new DefaultHttpClient(ccm, base.getParams());
} catch (Exception ex) {
return null;
}
}
Playstore 接受这个吗?有没有更好的方法来处理这个问题?
提前致谢。
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.URL;
import java.net.URLConnection;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.cert.X509Certificate;
public class Example {
public static void main(String[] args) throws Exception {
// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
}
}
};
// Install the all-trusting trust manager
SSLContext sc = SSLContext.getInstance("SSL"); // Add in try catch block if you get error.
sc.init(null, trustAllCerts, new java.security.SecureRandom()); // Add in try catch block if you get error.
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
// Create all-trusting host name verifier
HostnameVerifier allHostsValid = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
// Install the all-trusting host verifier
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
URL url = new URL("https_url_here");
URLConnection con = url.openConnection();
Reader reader = new InputStreamReader(con.getInputStream());
while (true) {
int ch = reader.read();
if (ch==-1) {
break;
}
System.out.print((char)ch);
}
}
}
使用这个技巧时要小心!跳过证书验证是危险的,只能在测试环境中进行。
引用解决方案: https://gist.github.com/aembleton/889392
以下代码禁用对 HttpsUrlConnection 的任何新实例的 SSL 证书检查:
/**
* Disables the SSL certificate checking for new instances of {@link HttpsURLConnection} This has been created to
* aid testing on a local box, not for use on production.
*/
public static void disableSSLCertificateChecking() {
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
@Override
public void checkClientTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
// Not implemented
}
@Override
public void checkServerTrusted(X509Certificate[] arg0, String arg1) throws CertificateException {
// Not implemented
}
} };
try {
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() { @Override public boolean verify(String hostname, SSLSession session) { return true; } });
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
}
如果有人想在 NativeScript Android 应用程序中禁用 SSL 证书检查,这里是将
const disableSSLCertificateCheckin = function () {
const trustAllCerts = [new javax.net.ssl.X509TrustManager({
getAcceptedIssuers: function () {
return null
},
checkClientTrusted: function (arg0, arg1) {
// Not implemented
},
checkServerTrusted: function (arg0, arg1) {
// Not implemented
},
})]
try {
const sc = javax.net.ssl.SSLContext.getInstance('TLS')
sc.init(null, trustAllCerts, new java.security.SecureRandom())
javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory())
javax.net.ssl.HttpsURLConnection.HttpsURLConnection.setDefaultHostnameVerifier(
new javax.net.ssl.HostnameVerifier({
verify: function (hostname, session) {
return true
}
})
)
} catch (e) {
console.log('e :>> ', e);
}
}
disableSSLCertificateCheckin()
谢谢