带有AndroidHttpClient的SSL / TLS协议和密码套件
这个很重要。众所周知,在服务器上可以做很多事情,但是有很多限制。同一台服务器必须为包括旧浏览器在内的浏览器以及其他客户端提供服务。这意味着服务器必须支持各种协议和密码。即使在Android中,如果您必须支持许多不同的版本,则也将必须支持许多不同的协议和密码。
更重要的是,默认情况下,在SSL握手期间,OpenSSL会遵守客户端的密码优先级, 而不是
服务器的密码优先级。例如,请参阅此文章,该文章说您可以通过设置SSL_OP_CIPHER_SERVER_PREFERENCE在客户端中覆盖该行为。尚不清楚是否可以在Java中的SSLSocket上设置此选项。即使可以,您也可以自己设置密码列表,也可以告诉客户端遵守服务器列表。否则,您将获得Android默认值,无论运行的版本是什么(而不是链接所针对的版本)。
如果采用默认值,则可以在此处从504行开始看到客户端发送的Jellybean
4.2+客户端的首选项列表。协议的默认列表从620行开始。尽管Jellybean
4.2+包括对OpenSSL的支持1.0.1,尤其是TLSv1.1和TLSv1.2,默认情况下未启用这些协议。如果您不做我做过的事情,则无法利用TLSv1.2支持,尽管事实上在最新版本的Android上宣传了对TLSv1.2的支持。当您返回以前的Android版本时,细节会有很大不同。至少,您可能希望仔细查看所有受支持版本的默认值,并查看客户端的实际操作。您可能会感到惊讶。
关于支持各种协议和密码,您可以说更多的话。关键是,有时可能需要在客户端中更改这些设置。
这对我来说效果很好,最后,它并不是很多代码。但是由于以下几个原因,它有点棘手:
- 有两个不同的SSLSocketFactory类。客户端需要一个org.apache.http.conn.ssl.SSLSocketFactory,但是OpenSSL返回一个javax.net.ssl.SSLSocketFactory。这绝对是令人困惑的。我使用委派使一个呼叫另一个,没有太大问题。
- 请注意OpenSSLContextImpl和SSLContextImpl之间的区别。一个只包装另一个,但不能互换。当我使用SSLContextImpl.engineGetSocketFactory方法时,我忘记了到底发生了什么,但是却悄无声息地失败了。确保使用OpenSSLContextImpl而不是SSLContextImpl来获取套接字工厂。您也许还可以使用javax.net.ssl.SSLSocketFactory.getDefault(),但我不确定。
- 您不能轻易地继承AndroidHttpClient的子类,因为它的构造函数是私有的。这很不幸,因为它还提供了其他一些好处,例如确保您将其正确关闭而不浪费资源。DefaultHttpClient正常工作。我从AndroidHttpClient(约105行)处借用了newInstance方法。
重点:
public class SecureSocketFactory extends SSLSocketFactory { @Override
public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
// order should not matter here; the server should select the highest
// one from this list that it supports
s.setEnabledProtocols(new String[] { "TLSv1.2", "TLSv1" });
// order matters here; specify in preference order
s.setEnabledCipherSuites(new String[] { "ECDHE-RSA-RC4-SHA", "RC4-SHA" });
然后:
// when creating clientHttpParams params;
SchemeRegistry schemeRegistry = new SchemeRegistry();
// use custom socket factory for https
SSLSocketFactory sf = new SecureSocketFactory();
schemeRegistry.register(new Scheme("https", sf, 443));
// use the default for http
schemeRegistry.register(new Scheme("http",
PlainSocketFactory.getSocketFactory(), 80));
ClientConnectionManager manager =
new ThreadSafeClientConnManager(params, schemeRegistry);
HttpClient client = new DefaultHttpClient(manager, params);
在Android 3.0(Honeycomb / SDK 11)以下版本中,受支持的密码选择变得更加有限,并且没有太多动机来覆盖默认设置。在FROYO /
SDK 8上,由于某种原因,我的SecureSocketFactory炸毁了,评审团在10名上脱颖而出。但是对于11点以上的工作似乎还不错。
完整的解决方案在公共github
仓库中。
另一个解决方案可能是使用HttpsUrlConnection,这使使用自定义套接字工厂变得容易,但是我想您可能会失去高级HTTP客户端的更多便利。我对HttpsUrlConnection没有任何经验。
回答:
使用AndroidHttpClient通过HTTPS发出REST请求时,如何指定要使用的SSL协议和密码?
我不相信您可以做到AndroidHttpClient
。我为加强通道所做的所有工作(例如密码列表,证书固定和公钥固定)都需要在某个地方自定义类,无论它是SSLSocketFactory
还是X509TrustManager
。那是Java,那是Android。请参阅使用HttpsURLConnection时如何覆盖由Android发送到服务器的密码列表?。
以上是 带有AndroidHttpClient的SSL / TLS协议和密码套件 的全部内容, 来源链接: utcz.com/qa/397303.html