我已经读过Android 8: Cleartext HTTP traffic not permitted,但是似乎没有一个答案可以让我做自己想做的事。
我有一个Android应用程序,另一个客户端可以使用证书来标识自己。应用程序要验证该证书。验证证书的一部分是从证书颁发者获取证书吊销列表(CRL)。 CRL的分发点已在证书中列出,并且不可避免地是HTTP URL(CRL本身由发行者签名,因此不存在安全问题,如果它是HTTPS URL,则将要验证保护CRL分发点的证书,并检查它是否已被撤销...)
可能的解决方案,以及为什么它们对我不起作用:
network_security_config.xml
,其中列出了允许HTTP访问的域。可悲的是,我在构建应用程序时不知道URL,这取决于CA决定将其放入证书中的内容。android:usesCleartextTraffic="true"
放在清单中。这意味着任何流量都可以是HTTP,如果可能的话,我宁愿避免这种情况。 (例如,与服务器的通信绝对必须是HTTPS,如果我不小心执行HTTP,我想出错。)代码是否可以通过任何方式说出“ 此连接允许使用HTTP”(但默认仅使用HTTPS)?
答案 0 :(得分:1)
NetworkSecurityPolicy.isCleartextTrafficPermitted()上的文档说
此标志是基于尽力而为的,因为鉴于提供给它们的访问级别,无法阻止来自Android应用程序的所有明文流量。例如,由于Socket API无法确定其流量是否为明文,因此没有期望set up a simple TCP client API将接受此标志。
因此,这也许是您的一个选择:使用Socket
获取CRL。丹尼尔·纽金特(Daniel Nugent)发表了一篇帖子,描述了如何{{3}}
答案 1 :(得分:0)
如果您使用的是OkHttp,则可以这样构造客户端:
OkHttpClient client = new OkHttpClient.Builder()
.connectionSpecs(Arrays.asList(ConnectionSpec.MODERN_TLS, ConnectionSpec.COMPATIBLE_TLS))
.build();
这将仅允许通过HTTPS进行连接。因此,您可以使用第三个选项(android:usesCleartextTraffic="true"
),当通过此客户端建立明文连接时,它将失败。
最后,您可以创建一个标准的OkHttp客户端:
OkHttpClient client = new OkHttpClient.Builder().build()
当您要使用明文连接时。
编辑:使用HttpUrlConnection
,您可以简单地检查返回的连接是否为HttpsUrlConnection
,例如:
try {
URL my_url = new URL(path);
HttpUrlConnection urlConnection = (HttpURLConnection) my_url.openConnection();
if(!(urlConnection instanceof HttpsURLConnection)) {
// cleartext connection, throw error
throw new NotHttpsException();
}
// the connection is secure, do normal stuff here
urlConnection.setRequestMethod("POST");
urlConnection.setConnectTimeout(1500);
urlConnection.setReadTimeout(1500);
result = IOUtil.readFully(urlConnection.getInputStream());
} catch(Exception e) {
e.printStackTrace()
} finally {
if(urlConnection != null) urlConnection.disconnect();
}
答案 2 :(得分:0)
该应用与服务器具有TLS连接。
您可以要求服务器向您移交那些CRL URL(首先移交证书,对吗?)。
它甚至可以事先做,并提供证书和CRL。
通过这种方式,您可以获取CRL,而无需松开https锁,也不必创建异常。