J'utilise retrofit dans Android pour me connecter au serveur.
public class ApiClient {
public static final String BASE_URL = "https://example.com/";
private static Retrofit retrofit = null;
public static Retrofit getClient() {
if (retrofit==null) {
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
}
return retrofit;
}
}
C'est mon dev. serveur et je veux désactiver la vérification de certificat. Comment puis-je implémenter dans ce code?
ERREUR: javax.net.ssl.SSLHandshakeException: Java.security.cert.CertPathValidatorException: L'ancre de confiance pour le chemin de certification introuvable.
Utilisez cette classe pour obtenir une instance de modification non sécurisée. J'ai inclus les importations pour éviter toute confusion.
import Java.security.cert.CertificateException;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import view.utils.AppConstants;
/**
* Created by Hitesh.Sahu on 11/23/2016.
*/
public class NetworkHandler {
public static Retrofit getRetrofit() {
return new Retrofit.Builder()
.baseUrl(AppConstants.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.client(getUnsafeOkHttpClient())
.build();
}
private static OkHttpClient getUnsafeOkHttpClient() {
try {
// Create a trust manager that does not validate certificate chains
final TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
@Override
public void checkClientTrusted(Java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public void checkServerTrusted(Java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
}
@Override
public Java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new Java.security.cert.X509Certificate[]{};
}
}
};
// Install the all-trusting trust manager
final SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new Java.security.SecureRandom());
// Create an ssl socket factory with our all-trusting manager
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.sslSocketFactory(sslSocketFactory);
builder.hostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
OkHttpClient okHttpClient = builder.build();
return okHttpClient;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
Et puis, utilisez simplement la modernisation sans vérification SSL comme celle-ci
private void postFeedbackOnServer() {
MyApiEndpointInterface apiService =
NetworkHandler.getRetrofit().create(MyApiEndpointInterface.class);
Call<ResponseBE> call = apiService.submitFeedbackToServer(requestObject);
Log.e(TAG , "Request is" + new Gson().toJson(requestObject).toString() );
call.enqueue(new Callback<ResponseBE>() {
@Override
public void onResponse(Call<ResponseBE> call, Response<ResponseBE> response) {
int statusCode = response.code();
if (statusCode == HttpURLConnection.HTTP_OK) {
......
} else {
Toast.makeText(FeedbackActivity.this, "Failed to submit Data" + statusCode, Toast.LENGTH_SHORT).show();
}
}
@Override
public void onFailure(Call<ResponseBE> call, Throwable t) {
// Log error here since request failed
Toast.makeText(FeedbackActivity.this, "Failure" + t.getLocalizedMessage(), Toast.LENGTH_SHORT).show();
}
});
}
Je déconseille fortement de le faire
Réponse courte - sous-classe HostNameVerifier, remplacez verify () pour toujours renvoyer true.
Cela a de meilleures options
Réponse longue - consultez mon blog (devenu assez vieux) ici: Faire fonctionner Android et SSL ensemble
Peut-être la meilleure option pour votre scénario
Déposez le https sur http pour votre serveur de test, la logique ne doit pas changer.
HTH
IMO, vous pouvez lire la documentation de Google - Sécurité avec HTTPS et SSL .
À propos des exemples de code à utiliser Retrofit avec votre certificat auto-signé, veuillez essayer ce qui suit, espérons que cela aidera!
...
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
try{
OkHttpClient client = new OkHttpClient.Builder()
.sslSocketFactory(getSSLSocketFactory())
.hostnameVerifier(getHostnameVerifier())
.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(API_URL_BASE)
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();
WebAPIService service = retrofit.create(WebAPIService.class);
Call<JsonObject> jsonObjectCall = service.getData(...);
...
} catch (Exception e) {
e.printStackTrace();
}
}
// for SSL...
// Read more at https://developer.Android.com/training/articles/security-ssl.html#CommonHostnameProbs
private HostnameVerifier getHostnameVerifier() {
return new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
return true; // verify always returns true, which could cause insecure network traffic due to trusting TLS/SSL server certificates for wrong hostnames
//HostnameVerifier hv = HttpsURLConnection.getDefaultHostnameVerifier();
//return hv.verify("localhost", session);
}
};
}
private TrustManager[] getWrappedTrustManagers(TrustManager[] trustManagers) {
final X509TrustManager originalTrustManager = (X509TrustManager) trustManagers[0];
return new TrustManager[]{
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return originalTrustManager.getAcceptedIssuers();
}
public void checkClientTrusted(X509Certificate[] certs, String authType) {
try {
if (certs != null && certs.length > 0){
certs[0].checkValidity();
} else {
originalTrustManager.checkClientTrusted(certs, authType);
}
} catch (CertificateException e) {
Log.w("checkClientTrusted", e.toString());
}
}
public void checkServerTrusted(X509Certificate[] certs, String authType) {
try {
if (certs != null && certs.length > 0){
certs[0].checkValidity();
} else {
originalTrustManager.checkServerTrusted(certs, authType);
}
} catch (CertificateException e) {
Log.w("checkServerTrusted", e.toString());
}
}
}
};
}
private SSLSocketFactory getSSLSocketFactory()
throws CertificateException, KeyStoreException, IOException,
NoSuchAlgorithmException, KeyManagementException {
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream caInput = getResources().openRawResource(R.raw.your_cert); // File path: app\src\main\res\raw\your_cert.cer
Certificate ca = cf.generateCertificate(caInput);
caInput.close();
KeyStore keyStore = KeyStore.getInstance("BKS");
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
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();
}
...
La syntaxe a un peu changé depuis la réponse de Hitesh Sahu. Maintenant, vous pouvez utiliser lambdas pour certaines méthodes, supprimer des clauses throw et des invocations de méthodes de constructeur de chaînes.
private static OkHttpClient createOkHttpClient() {
try {
final TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
@Override
public void checkClientTrusted(Java.security.cert.X509Certificate[] chain, String authType) {}
@Override
public void checkServerTrusted(Java.security.cert.X509Certificate[] chain, String authType) {}
@Override
public Java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new Java.security.cert.X509Certificate[]{};
}
}
};
final SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trustAllCerts, new Java.security.SecureRandom());
return new OkHttpClient.Builder()
.sslSocketFactory(sslContext.getSocketFactory())
.hostnameVerifier((hostname, session) -> true)
.build();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
La mise en œuvre de cette solution de contournement dans le code, même à des fins de test, est une mauvaise pratique.
Vous pouvez:
Quelques liens qui peuvent être utiles:
private boolean bypassSSLVerification = true;
private boolean privateCA = false;
if(bypassSSLVerification)
{
IO.setDefaultSSLContext(SSLContextManager.getTrustAllSSLContext());
IO.setDefaultHostnameVerifier(new HostnameVerifier()
{
@Override
public boolean verify(String s, SSLSession sslSession)
{
return true;
}
});
}
else if(privateCA)
{
IO.setDefaultSSLContext(SSLContextManager.getSSLContext(context));
}
SSLContextManager.Java
public class SSLContextManager
{
public static SSLContext getSSLContext(Context context) throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException, KeyManagementException, NoSuchProviderException
{
// Load CAs from an InputStream
CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC");
InputStream cert = context.getResources().openRawResource(R.raw.my_cert); // Place your 'my_cert.crt' file in `res/raw`
Certificate ca;
try
{
ca = cf.generateCertificate(cert);
}
finally
{
cert.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 sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
return sslContext;
}
public static SSLContext getTrustAllSSLContext() throws NoSuchAlgorithmException, KeyManagementException
{
// Create a trust manager that does not validate certificate chains
final TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
@Override
public void checkClientTrusted(Java.security.cert.X509Certificate[] chain, String authType) {
}
@Override
public void checkServerTrusted(Java.security.cert.X509Certificate[] chain, String authType){
}
@Override
public Java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new Java.security.cert.X509Certificate[]{};
}
}
};
// Install the all-trusting trust manager
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustAllCerts, new Java.security.SecureRandom());
return sslContext;
}
}