android https 简书,Android5.0以下支持https请求

萌新在今天弄了一天才解决【哭~】,虽然现在手机发展很迅速,但是还有一些是5.0以下的机型,把今天遇到的问题记录一下,

萌新解决问题翻到的一些文章

官方的文档显示,在API 16+以上,TLS1.1和TLS1.2是默认开启的。但是实际上在API 20+以上才默认开启,4.4以下的版本是无法使用TLS1.1和TLS 1.2的,这也是Android系统的一个bug。

关键代码

1.定义一个类继承SSLSocketFactory 开启TLS1.1和TLS1.2

public class SSLSocketFactoryCompat extends SSLSocketFactory {

private SSLSocketFactory defaultFactory;

// Android 5.0+ (API level21) provides reasonable default settings

// but it still allows SSLv3

// https://developer.android.com/about/versions/android-5.0-changes.html#ssl

static String protocols[] = null, cipherSuites[] = null;

static {

try {

SSLSocket socket = (SSLSocket) SSLSocketFactory.getDefault().createSocket();

if (socket != null) {

/* set reasonable protocol versions */

// - enable all supported protocols (enables TLSv1.1 and TLSv1.2 on Android <5.0)

// - remove all SSL versions (especially SSLv3) because they're insecure now

List protocols = new LinkedList<>();

for (String protocol : socket.getSupportedProtocols())

if (!protocol.toUpperCase().contains("SSL"))

protocols.add(protocol);

SSLSocketFactoryCompat.protocols = protocols.toArray(new String[protocols.size()]);

/* set up reasonable cipher suites */

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {

// choose known secure cipher suites

List allowedCiphers = Arrays.asList(

// TLS 1.2

"TLS_RSA_WITH_AES_256_GCM_SHA384",

"TLS_RSA_WITH_AES_128_GCM_SHA256",

"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",

"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",

"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",

"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256",

"TLS_ECHDE_RSA_WITH_AES_128_GCM_SHA256",

// maximum interoperability

"TLS_RSA_WITH_3DES_EDE_CBC_SHA",

"TLS_RSA_WITH_AES_128_CBC_SHA",

// additionally

"TLS_RSA_WITH_AES_256_CBC_SHA",

"TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",

"TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA",

"TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",

"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA");

List availableCiphers = Arrays.asList(socket.getSupportedCipherSuites());

// take all allowed ciphers that are available and put them into preferredCiphers

HashSet preferredCiphers = new HashSet<>(allowedCiphers);

preferredCiphers.retainAll(availableCiphers);

/* For maximum security, preferredCiphers should *replace* enabled ciphers (thus disabling

* ciphers which are enabled by default, but have become unsecure), but I guess for

* the security level of DAVdroid and maximum compatibility, disabling of insecure

* ciphers should be a server-side task */

// add preferred ciphers to enabled ciphers

HashSet enabledCiphers = preferredCiphers;

enabledCiphers.addAll(new HashSet<>(Arrays.asList(socket.getEnabledCipherSuites())));

SSLSocketFactoryCompat.cipherSuites = enabledCiphers.toArray(new String[enabledCiphers.size()]);

}

}

} catch (IOException e) {

throw new RuntimeException(e);

}

}

public SSLSocketFactoryCompat(X509TrustManager tm) {

try {

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

sslContext.init(null, (tm != null) ? new X509TrustManager[]{tm} : null, null);

defaultFactory = sslContext.getSocketFactory();

} catch (GeneralSecurityException e) {

throw new AssertionError(); // The system has no TLS. Just give up.

}

}

private void upgradeTLS(SSLSocket ssl) {

// Android 5.0+ (API level21) provides reasonable default settings

// but it still allows SSLv3

// https://developer.android.com/about/versions/android-5.0-changes.html#ssl

if (protocols != null) {

ssl.setEnabledProtocols(protocols);

}

if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP && cipherSuites != null) {

ssl.setEnabledCipherSuites(cipherSuites);

}

}

@Override

public String[] getDefaultCipherSuites() {

return cipherSuites;

}

@Override

public String[] getSupportedCipherSuites() {

return cipherSuites;

}

@Override

public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {

Socket ssl = defaultFactory.createSocket(s, host, port, autoClose);

if (ssl instanceof SSLSocket)

upgradeTLS((SSLSocket) ssl);

return ssl;

}

@Override

public Socket createSocket(String host, int port) throws IOException, UnknownHostException {

Socket ssl = defaultFactory.createSocket(host, port);

if (ssl instanceof SSLSocket)

upgradeTLS((SSLSocket) ssl);

return ssl;

}

@Override

public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {

Socket ssl = defaultFactory.createSocket(host, port, localHost, localPort);

if (ssl instanceof SSLSocket)

upgradeTLS((SSLSocket) ssl);

return ssl;

}

@Override

public Socket createSocket(InetAddress host, int port) throws IOException {

Socket ssl = defaultFactory.createSocket(host, port);

if (ssl instanceof SSLSocket)

upgradeTLS((SSLSocket) ssl);

return ssl;

}

@Override

public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {

Socket ssl = defaultFactory.createSocket(address, port, localAddress, localPort);

if (ssl instanceof SSLSocket)

upgradeTLS((SSLSocket) ssl);

return ssl;

}

}

2.定义一个信任所有证书的TrustManager

final X509TrustManager trustAllCert = 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[]{};

}

OkHttp:

定义自己的httpclient:hostnameVerifier 并返回true或者判断自己app支持的域名,这个方法很重要,之前我不加上这个,没有效果

OkHttpClient client = new OkHttpClient.Builder()

.hostnameVerifier(new HostnameVerifier() {

@Override

public boolean verify(String hostname, SSLSession session) {

// if (hostname.equals("https://www.baidu.com")){

// return true

// }

return true;

}

})

.addInterceptor(new RequestLogInterceptor())

.sslSocketFactory(new SSLSocketFactoryCompat(trustAllCert), trustAllCert)

.addInterceptor(new RequestHeaderInterceptor())

.cache(cache)

.build();

mRetrofit = new Retrofit.Builder()

.client(client)

.baseUrl(baseUrl)

.addConverterFactory(GsonConverterFactory.create())

.addCallAdapterFactory(RxJava2CallAdapterFactory.create())

.build();

Volley:

在new XXXRequest()之前加上

HttpsURLConnection.setDefaultSSLSocketFactory(new SSLSocketFactoryCompat(trustAllCert));

mQueue = Volley.newRequestQueue(context);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值