我开始提问。我想在Android上解决问题,但不知道如何解决。我花了很多时间在网上寻找解决方案,但在任何地方都找不到关于此问题的单一讨论。尽管如此,包括StackOverflow线程在内的一些讨论让我看到了一种前景看好的技术。我解决了这个问题。但解决方案有点牵扯。所以我决定在这里发布这个问题,思考a)必须有一个更好的解决方案,并希望有人知道并在这里发布答案;或者b)也许这是一个很好的解决方案,因为我发现网上其他任何地方都没有讨论过这个问题,也许我对这个问题的解决方案对于其他试图做同样事情的人来说也是有用的。无论哪种方式,结果都将是对StackOverflow的新贡献:一个在其他地方无法回答的问题,最终会以某种方式回答正确答案。实际上,StackOverflow甚至邀请我在我最初发布它时通过分享我的知识来回答我自己的问题。事实上,那是我动机的一部分。即使是这件事的事实也没有收集到我找到的任何地方。
所以:
问。使用AndroidHttpClient通过HTTPS发出REST请求时,如何指定要使用的SSL协议和密码?
这很重要。很明显,服务器上可以做很多事情,但是有限制。同一台服务器必须提供浏览器,包括旧浏览器以及其他客户端。这意味着服务器必须支持广泛的协议和密码。即使在Android中,如果你必须支持许多不同的版本,你将不得不支持许多不同的协议和密码。
更重要的是,默认情况下,OpenSSL在SSL握手期间尊重客户端的密码首选项而不是服务器。例如,请参阅此post,其中说明您可以通过设置SSL_OP_CIPHER_SERVER_PREFERENCE来覆盖客户端中的该行为。如果甚至可以在Java中的SSLSocket上设置此选项,则不完全清楚。即使可以,您也可以自己设置密码列表或告诉客户尊重服务器列表。否则,您将获得Android默认设置,无论您运行的版本是什么(不是您链接的版本)。
如果采用默认设置,Jellybean 4.2+客户端从客户端发送到服务器的首选项列表可以看到here,从第504行开始。默认的协议列表从第620行开始。 Jellybean 4.2+包括对OpenSSL 1.0.1的支持,特别是TLSv1.1和TLSv1.2,默认情况下不启用这些协议。如果你没有像我所做的那样做,你就无法利用TLSv1.2的支持,尽管在最新版本的Android上宣传了对TLSv1.2的支持。回顾以前的Android版本,细节会有很大差异。至少,您可能希望仔细查看所有受支持版本的默认值,并查看客户端实际执行的操作。你可能会感到惊讶。
关于对各种协议和密码的支持,你可以说更多。关键是,有时可能需要在客户端中更改这些设置。
:一种。使用自定义SSLSocketFactory
这对我来说效果很好,最后代码不是很多。但由于以下几个原因,这有点棘手:
关键点:
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 client
HttpParams 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 repo。
另一个解决方案可能是使用HttpsUrlConnection,这使得使用自定义套接字工厂变得容易,但我想你可能会失去更多高级HTTP客户端的便利性。我对HttpsUrlConnection没有任何经验。
答案 0 :(得分:1)
使用AndroidHttpClient通过HTTPS发出REST请求时,如何指定要使用的SSL协议和密码?
我认为你不能用AndroidHttpClient
做到这一点。我为加强频道所做的一切(如密码列表,证书固定和公钥固定)都需要在某个地方使用自定义类,无论是SSLSocketFactory
还是X509TrustManager
。那是Java,那是Android。请参阅How to override the cipherlist sent to the server by Android when using HttpsURLConnection?。