gpt4 book ai didi

android - 在Android中使用自签名证书实现https连接的正确方法是什么?

转载 作者:太空宇宙 更新时间:2023-11-03 15:12:24 26 4
gpt4 key购买 nike

我已经在Stack Overflow上看到了与该主题相关的几乎所有问题,但找不到解决方案。

根据documentation,我们可以使用自签名证书,如下所示:

// Load CAs from an InputStream
// (could be from a resource or ByteArrayInputStream or ...)
CertificateFactory cf = CertificateFactory.getInstance("X.509");
InputStream caInput = new BufferedInputStream(new FileInputStream("mycert.crt"));
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
System.out.println("ca=" + ((X509Certificate) ca).getSubjectDN());
} 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
URL url = new URL("https://ip/address");
HttpsURLConnection urlConnection =
(HttpsURLConnection)url.openConnection();
urlConnection.setSSLSocketFactory(context.getSocketFactory());
InputStream in = urlConnection.getInputStream();
copyInputStreamToOutputStream(in, System.out);


但这将引发java.security.cert.CertPathValidatorException:


  javax.net.ssl.SSLHandshakeException:
  java.security.cert.CertPathValidatorException:的信任锚
  找不到认证路径。


还尝试了这个:

InputStream keystoreInput = context.getResources().openRawResource(R.raw.cert_keystore);

KeyStore keyStore = KeyStore.getInstance("bks");
keyStore.load(keystoreInput, "pass".toCharArray());

KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509");
kmf.init(keyStore, "pass".toCharArray());

TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509");
tmf.init(keyStore);

SSLContext context= SSLContext.getInstance("TLS");


context.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);


URL url = new URL("https://ip/address");
HttpsURLConnection urlConnection =
(HttpsURLConnection)url.openConnection();
urlConnection.setSSLSocketFactory(context.getSocketFactory());
InputStream in = urlConnection.getInputStream();


但这会产生相同的错误。

另外,我可以确保证书有效,因为我可以按以下方式发布请求:

curl -v -s -k --key mykey.key--cert mycert.crt -X GET "https://ip/path"


在Android中使用自签名证书实现https连接的正确方法是什么(无需额外的库,仅使用HttpsUrlConnection)?

注意:我不想使用任何库,包括 OkHttpApache等。

更新

终于找到了解决方案,这是主要部分:

InputStream keystoreInput = context.getResources().openRawResource(R.raw.cert_keystore);

KeyStore keyStore = KeyStore.getInstance("bks");
keyStore.load(keystoreInput, "pass".toCharArray());

KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509");
kmf.init(keyStore, "pass".toCharArray());


SSLContext context= SSLContext.getInstance("TLS");


context.init(kmf.getKeyManagers(), new TrustManager[] {new X509TrustManager() {
@Override
public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {}

@Override
public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {}

@Override
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}}, null);


URL url = new URL("https://ip/address");
HttpsURLConnection urlConnection =
(HttpsURLConnection)url.openConnection();

urlConnection.setSSLSocketFactory(context.getSocketFactory());

// skip hostname security check
urlConnection.setHostnameVerifier(new AllowAllHostnameVerifier());
InputStream in = urlConnection.getInputStream();


但是我不确定是否存在使用自签名证书实现HTTPS连接的更安全的方法。

“系统使用 TrustManager来验证来自服务器的证书,并且通过从具有一个或多个CA的 KeyStore创建一个证书,这些证书将是该 TrustManager唯一信任的CA。” doc

因此,我们需要实现 TrustManager,但是我们应该怎么做呢?
任何建议都会有所帮助。

谢谢

最佳答案

在您的WebServiceHelper类中,请使用以下方法:

public class WebServiceHelper {
public static final String ENDPOINT = "your address";
private static WebServiceHelper instance;
private Services service;
private Context mContext;

private OkHttpClient getMyOkHttpClient(String serverUrl) {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
if (BuildConfig.DEBUG) {
builder.interceptors().add((new HttpLoggingInterceptor()).setLevel(HttpLoggingInterceptor.Level.BODY));
} else {
builder.interceptors().add((new HttpLoggingInterceptor()).setLevel(HttpLoggingInterceptor.Level.NONE));
}
builder.cookieJar(new JavaNetCookieJar(new CookieManager()))
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(60, TimeUnit.SECONDS)
.writeTimeout(120, TimeUnit.SECONDS);

if ((serverUrl.toLowerCase()).contains("https")) initUnSafeSSL(builder);
return builder.build();
}

private void initUnSafeSSL(OkHttpClient.Builder builder1) {
try {
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());
final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
builder1.sslSocketFactory(sslSocketFactory, (X509TrustManager) trustAllCerts[0]);
builder1.hostnameVerifier((hostname, session) -> true);
} catch (Exception e) {
throw new RuntimeException(e);
}
}

private WebServiceHelper(Context context) {
mContext = context;
Retrofit retrofit = createAdapter(ENDPOINT).build();
service = retrofit.create(Services.class);
}

public static WebServiceHelper getInstance(Context context) {
if (instance == null) {
instance = new WebServiceHelper(context);
}
return instance;
}

private Retrofit.Builder createAdapter(String serverChoice) {
return new Retrofit.Builder()
.baseUrl(serverChoice)
.client(getMyOkHttpClient(serverChoice))
.addConverterFactory(GsonConverterFactory.create());
}

关于android - 在Android中使用自签名证书实现https连接的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52294588/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com