Androidでレトロフィットを使用してサーバーに接続しています。
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;
}
}
これが私の開発者です。サーバーと証明書のチェックを無効にします。このコードでどのように実装できますか?
エラー:javax.net.ssl.SSLHandshakeException:Java.security.cert.CertPathValidatorException:証明書パスのトラストアンカーが見つかりません。
このクラスを使用して、安全でないRetrofitインスタンスを取得します。混乱を避けるためにインポートを含めました。
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);
}
}
}
そして、このようなSSLチェックなしで単にレトロフィットを使用します
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();
}
});
}
これを行うことは強くお勧めしません
短い答え-サブクラスHostNameVerifier、常にtrueを返すためにverify()をオーバーライドします。
これにはより良いオプションがあります
長い答え-私の(かなり古くなった)ブログをチェックしてください: Make Android and SSL Work Together
おそらくあなたのシナリオに最適なオプションです
テストサーバーのhttpsをhttpにドロップすれば、ロジックを変更する必要はありません。
HTH
Hitesh Sahuの回答が投稿されてから、構文が少し変更されました。これで、一部のメソッドにラムダを使用し、いくつかのthrow句を削除して、ビルダーのメソッド呼び出しをチェーンできます。
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);
}
}
IMO、あなたは読むことができます Googleのドキュメント-HTTPSとSSLによるセキュリティ 。
自己署名証明書でRetrofitを使用するサンプルコードについては、次のことを試してください。
...
@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();
}
...
このような回避策をコードに実装することは、テスト目的であっても悪い習慣です。
あなたはできる:
役に立つかもしれないいくつかのリンク:
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;
}
}