Как исправить небезопасную реализацию X509TrustManager в приложении для Android
Google сообщила, что у меня есть небезопасная реализация интерфейса X509TrustManager в приложении для Android и мне нужно изменить свой код следующим образом:
Чтобы правильно обрабатывать SSL-сертификат, измените код в checkServerTrusted метод вашего пользовательского интерфейса X509TrustManager для поднять либо CertificateException, либо IllegalArgumentException всякий раз сертификат, представленный сервером, не соответствует вашему ожидания. По техническим вопросам вы можете отправлять сообщения в Qaru и используйте теги "android-security" и "TrustManager".
Как можно изменить следующий код, чтобы исправить вышеупомянутую проблему?
public EasySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
super(truststore);
TrustManager tm = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
mContext.init(null, new TrustManager[] { tm }, null);
}
Ответы
Ответ 1
Я решил это, используя следующий код:
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
try {
chain[0].checkValidity();
} catch (Exception e) {
throw new CertificateException("Certificate not valid or trusted.");
}
}
Ответ 2
Если вы столкнулись с этим из внешней библиотеки, которую вы используете, проверьте, является ли ее причиной личная библиотека приложений.
Для меня библиотека apache вызвала ошибку: я использовал устаревший класс - MultipartEntity. Этот класс использует SSLContextBuilder
который использует TrustManagerDelegate. TrustManagerDelegate реализует X509TrustManager, что приводит к ошибке "небезопасной реализации TrustManager" при загрузке приложения в магазин воспроизведения Google.
Решение: вместо устаревшего MultipartEntity класса используйте MultipartEntityBuilder.
Например:
MultipartEntity httpMultipart = new MultipartEntity();
String contentType = httpMultipart.getContentType().getValue();
Будет заменено на:
MultipartEntityBuilder httpMultipart = new MultipartEntityBuilder();
String contentType = httpMultipart.build().getContentType().getValue();
Ответ 3
Я встречаюсь с этой проблемой. Если ваш код такой:
TrustManager tm = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
он примет весь сертификат, и это плохая идея, поэтому Google отправит вам письмо.
Мы также можем внести изменения, чтобы принять самозаверяющий сертификат.
Я решил это, вот мой вопрос и мое решение
Ответ 4
Если вы используете HttpClient
, то решение @Nabeel очень приятно, но если вы используете HttpsUrlConnection
, то этот код очень хорош для этого
import android.util.Log;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
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;
/**
* TrustManager that accepts all certificates and hosts.
* Useful when you want to use HTTPS but you have self-signed certificates.
* Works with HttpsUrlConnection.
* Use at your own risk and only for development.
*
* @author gotev (Aleksandar Gotev)
*/
public class AllCertificatesAndHostsTruster implements TrustManager, X509TrustManager {
@Override
public final void checkClientTrusted(final X509Certificate[] xcs, final String string)
throws CertificateException {
}
@Override
public final void checkServerTrusted(final X509Certificate[] xcs, final String string)
throws CertificateException {
}
@Override
public final X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
/**
* Gets an {@link SSLContext} which trusts all certificates.
* @return {@link SSLContext}
*/
public static SSLContext getSSLContext() {
final TrustManager[] trustAllCerts =
new TrustManager[] {new AllCertificatesAndHostsTruster()};
try {
final SSLContext context = SSLContext.getInstance("SSL");
context.init(null, trustAllCerts, new SecureRandom());
return context;
} catch (Exception exc) {
Log.e("CertHostTruster", "Unable to initialize the Trust Manager to trust all the "
+ "SSL certificates and HTTPS hosts.", exc);
return null;
}
}
/**
* Creates an hostname verifier which accepts all hosts.
* @return {@link HostnameVerifier}
*/
public static HostnameVerifier getAllHostnamesVerifier() {
return new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
}
/**
* Call this method once before all your network calls
* to accept all the self-signed certificates in HTTPS connections.
*/
public static void apply() {
final TrustManager[] trustAllCerts =
new TrustManager[] {new AllCertificatesAndHostsTruster()};
try {
final SSLContext context = SSLContext.getInstance("SSL");
context.init(null, trustAllCerts, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
} catch (Exception exc) {
Log.e("CertHostTruster", "Unable to initialize the Trust Manager to trust all the "
+ "SSL certificates and HTTPS hosts.", exc);
}
}
}
Источник: https://gist.github.com/gotev/6784c1303793c6ee9e56
Затем, чтобы использовать самозаверяющие сертификаты, просто вызовите:
AllCertificatesAndHostsTruster.apply();
перед любыми сетевыми вызовами.